new inference: process varargs as separate method candidate/separate phase

(cherry picked from commit fdd6f66268d29bb996a103f69180851b92947d21)
This commit is contained in:
Anna Kozlova
2014-03-10 19:51:22 +01:00
parent 69c6b7b523
commit 10760d9bbf
16 changed files with 221 additions and 126 deletions

View File

@@ -56,7 +56,7 @@ public class JavaMethodResolveHelper {
@Override
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor,
final boolean staticProblem,
final boolean accessible) {
final boolean accessible, final boolean varargs) {
return JavaMethodResolveHelper.this
.createCandidateInfo(method, substitutor, staticProblem, myCurrentFileContext, !accessible, argumentList, argumentTypes,
languageLevel);

View File

@@ -75,6 +75,10 @@ public class MethodCandidateInfo extends CandidateInfo{
myLanguageLevel = languageLevel;
}
public boolean isVarargs() {
return false;
}
public boolean isApplicable(){
return getApplicabilityLevel() != ApplicabilityLevel.NOT_APPLICABLE;
}
@@ -113,7 +117,7 @@ public class MethodCandidateInfo extends CandidateInfo{
CURRENT_CANDIDATE.set(map);
}
final PsiMethod method = getElement();
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, false, true);
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
try {
properties.setSubstitutor(substitutor);
@@ -122,7 +126,11 @@ public class MethodCandidateInfo extends CandidateInfo{
return ApplicabilityLevel.NOT_APPLICABLE;
}
return PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
if (!isVarargs() && applicabilityLevel < ApplicabilityLevel.FIXED_ARITY) {
return ApplicabilityLevel.NOT_APPLICABLE;
}
return applicabilityLevel;
}
finally {
if (alreadyThere == null) map.remove(getMarkerList());
@@ -242,9 +250,10 @@ public class MethodCandidateInfo extends CandidateInfo{
CURRENT_CANDIDATE.set(map);
}
final PsiMethod method = getElement();
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(),
new CurrentCandidateProperties(method, super.getSubstitutor(), false, //todo
!includeReturnConstraint));
final CurrentCandidateProperties alreadyThere = map.get(getMarkerList());
if (alreadyThere == null) {
map.put(getMarkerList(), new CurrentCandidateProperties(method, super.getSubstitutor(), isVarargs(), !includeReturnConstraint));
}
try {
PsiTypeParameter[] typeParameters = method.getTypeParameters();
@@ -297,6 +306,16 @@ public class MethodCandidateInfo extends CandidateInfo{
return myArgumentTypes;
}
@Override
public boolean equals(Object o) {
return super.equals(o) && isVarargs() == ((MethodCandidateInfo)o).isVarargs();
}
@Override
public int hashCode() {
return 31 * super.hashCode() + (isVarargs() ? 1 : 0);
}
public static class CurrentCandidateProperties {
private final PsiMethod myMethod;
private PsiSubstitutor mySubstitutor;
@@ -331,7 +350,7 @@ public class MethodCandidateInfo extends CandidateInfo{
}
public boolean isApplicabilityCheck() {
return myApplicabilityCheck && !ourOverloadGuard.currentStack().isEmpty();
return myApplicabilityCheck;
}
public void setApplicabilityCheck(boolean applicabilityCheck) {

View File

@@ -148,7 +148,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
}
staticFactoryRef.set(staticFactory);
return inferTypeParametersForStaticFactory(staticFactory, newExpression, context);
return inferTypeParametersForStaticFactory(staticFactory, newExpression, context, false);
}
});
if (inferredSubstitutor == null) {
@@ -297,12 +297,18 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod,
PsiNewExpression expression,
final PsiElement parent) {
final PsiElement parent,
final boolean varargs) {
final PsiExpressionList argumentList = expression.getArgumentList();
if (argumentList != null) {
final MethodCandidateInfo staticFactoryCandidateInfo =
new MethodCandidateInfo(staticFactoryMethod, PsiSubstitutor.EMPTY, false, false, argumentList, parent,
argumentList.getExpressionTypes(), null) {
@Override
public boolean isVarargs() {
return varargs;
}
@Override
protected PsiElement getParent() {
return parent;
@@ -313,6 +319,9 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
}
};
if (!varargs && staticFactoryMethod.isVarArgs() && staticFactoryCandidateInfo.getPertinentApplicabilityLevel() < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
}
return staticFactoryCandidateInfo.getSubstitutor();
}
else {

View File

@@ -90,16 +90,25 @@ public class InferenceSession {
}
public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod method) {
final MethodCandidateInfo.CurrentCandidateProperties currentProperties = getCurrentProperties(parent);
initExpressionConstraints(parameters, args, parent, method, currentProperties != null && currentProperties.isVarargs());
}
public void initExpressionConstraints(PsiParameter[] parameters,
PsiExpression[] args,
PsiElement parent,
PsiMethod method,
boolean varargs) {
final MethodCandidateInfo.CurrentCandidateProperties currentProperties = getCurrentProperties(parent);
if (method == null) {
final MethodCandidateInfo.CurrentCandidateProperties pair = getCurrentProperties(parent);
if (pair != null) {
method = pair.getMethod();
if (currentProperties != null) {
method = currentProperties.getMethod();
}
}
if (parameters.length > 0) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null && isPertinentToApplicability(args[i], method)) {
PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor);
PsiType parameterType = getParameterType(parameters, i, mySiteSubstitutor, varargs);
myConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
}
@@ -175,31 +184,11 @@ public class InferenceSession {
return true;
}
private PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, @Nullable PsiSubstitutor substitutor) {
private static PsiType getParameterType(PsiParameter[] parameters, int i, @Nullable PsiSubstitutor substitutor, boolean varargs) {
if (substitutor == null) return null;
PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType());
if (parameterType instanceof PsiEllipsisType) {
final PsiExpression arg = args[i];
if (arg instanceof PsiNewExpression) {
if (((PsiNewExpression)arg).getArrayDimensions().length == parameterType.getArrayDimensions() || ((PsiNewExpression)arg).getArrayInitializer() != null) {
return parameterType;
}
}
if (arg instanceof PsiCallExpression) {
final PsiMethod method = ((PsiCallExpression)arg).resolveMethod();
if (method != null) {
final PsiType returnType = method.getReturnType();
if (returnType != null && returnType.getArrayDimensions() == parameterType.getArrayDimensions()) {
return parameterType;
}
}
}
if (args.length != parameters.length ||
PsiPolyExpressionUtil.isPolyExpression(arg) ||
arg != null && !(arg.getType() instanceof PsiArrayType)) {
parameterType = ((PsiEllipsisType)parameterType).getComponentType();
}
if (parameterType instanceof PsiEllipsisType && varargs) {
parameterType = ((PsiEllipsisType)parameterType).getComponentType();
}
return parameterType;
}
@@ -209,17 +198,18 @@ public class InferenceSession {
return infer(null, null, null);
}
private PsiSubstitutor tryToInfer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiCallExpression parent,
@Nullable MethodCandidateInfo.CurrentCandidateProperties properties) {
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent) {
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
if (!repeatInferencePhases(true)) {
//inferred result would be checked as candidate won't be applicable
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
}
if (properties != null && !properties.isApplicabilityCheck()) {
initReturnTypeConstraint(properties.getMethod(), parent);
initReturnTypeConstraint(properties.getMethod(), (PsiCallExpression)parent);
if (!repeatInferencePhases(true)) {
return prepareSubstitution();
}
@@ -227,7 +217,7 @@ public class InferenceSession {
if (parameters != null && args != null) {
final Set<ConstraintFormula> additionalConstraints = new HashSet<ConstraintFormula>();
if (parameters.length > 0) {
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints);
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
@@ -236,53 +226,6 @@ public class InferenceSession {
}
}
return null;
}
private void collectAdditionalConstraints(PsiParameter[] parameters,
PsiExpression[] args,
PsiMethod parentMethod,
PsiSubstitutor siteSubstitutor,
Set<ConstraintFormula> additionalConstraints) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
PsiType parameterType = getParameterType(parameters, args, i, siteSubstitutor);
if (!isPertinentToApplicability(args[i], parentMethod)) {
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
if (args[i] instanceof PsiCallExpression) {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
final PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
final JavaResolveResult result = callExpression.resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
LOG.assertTrue(method != null);
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(), additionalConstraints);
}
}
}
}
}
}
}
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent) {
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
final PsiSubstitutor subst = tryToInfer(parameters, args, parent instanceof PsiCallExpression ? ((PsiCallExpression)parent) : null, properties);
if (subst != null) {
return subst;
}
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor);
if (substitutor != null) {
if (myContext != null) {
@@ -302,6 +245,42 @@ public class InferenceSession {
return prepareSubstitution();
}
private static void collectAdditionalConstraints(PsiParameter[] parameters,
PsiExpression[] args,
PsiMethod parentMethod,
PsiSubstitutor siteSubstitutor,
Set<ConstraintFormula> additionalConstraints,
boolean varargs) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
PsiType parameterType = getParameterType(parameters, i, siteSubstitutor, varargs);
if (!isPertinentToApplicability(args[i], parentMethod)) {
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
if (args[i] instanceof PsiCallExpression) {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
final PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
final JavaResolveResult result = callExpression.resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
LOG.assertTrue(method != null);
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(),
additionalConstraints, ((MethodCandidateInfo)result).isVarargs());
}
}
}
}
}
}
}
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
for (InferenceVariable variable : variables) {
@@ -486,7 +465,7 @@ public class InferenceSession {
return false;
}
private PsiType getTargetType(final PsiExpression context) {
private static PsiType getTargetType(final PsiExpression context) {
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent());
if (parent instanceof PsiExpressionList) {
PsiElement gParent = parent.getParent();
@@ -498,16 +477,17 @@ public class InferenceSession {
if (argumentList != null) {
final MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
if (properties != null && properties.isApplicabilityCheck()) {
return getTypeByMethod(context, argumentList, properties.getMethod(), properties.getSubstitutor());
return getTypeByMethod(context, argumentList, properties.getMethod(), properties.isVarargs(), properties.getSubstitutor());
}
final JavaResolveResult result = ((PsiCallExpression)gParent).resolveMethodGenerics();
final boolean varargs = properties != null && properties.isVarargs() || result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isVarargs();
return getTypeByMethod(context, argumentList, result.getElement(),
varargs,
PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false,
new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
return result
.getSubstitutor();
return result.getSubstitutor();
}
}
)
@@ -531,9 +511,11 @@ public class InferenceSession {
return null;
}
private PsiType getTypeByMethod(PsiExpression context,
PsiExpressionList argumentList,
PsiElement parentMethod, PsiSubstitutor substitutor) {
private static PsiType getTypeByMethod(PsiExpression context,
PsiExpressionList argumentList,
PsiElement parentMethod,
boolean varargs,
PsiSubstitutor substitutor) {
if (parentMethod instanceof PsiMethod) {
final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters();
if (parameters.length == 0) return null;
@@ -545,7 +527,7 @@ public class InferenceSession {
}
final int i = ArrayUtilRt.find(args, arg);
if (i < 0) return null;
return getParameterType(parameters, args, i, substitutor);
return getParameterType(parameters, i, substitutor, varargs);
}
return null;
}

View File

@@ -129,7 +129,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (method != null) {
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method);
callSession.initExpressionConstraints(parameters, args, myExpression, method, resolveResult instanceof MethodCandidateInfo && ((MethodCandidateInfo)resolveResult).isVarargs());
}
final boolean accepted = callSession.repeatInferencePhases(true);
if (!accepted) {

View File

@@ -445,20 +445,31 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
final PsiConflictResolver conflictResolver = createResolver(qualifierResolveResult, interfaceMethod, signature);
final MethodCandidatesProcessor processor =
new MethodCandidatesProcessor(reference, getContainingFile(), new PsiConflictResolver[] {conflictResolver}, new SmartList<CandidateInfo>()) {
@Override
protected boolean acceptVarargs() {
return true;
}
@Override
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method,
final PsiSubstitutor substitutor,
final boolean staticProblem,
final boolean accessible) {
final boolean accessible,
final boolean varargs) {
final PsiExpressionList argumentList = getArgumentList();
final PsiType[] typeParameters = reference.getTypeParameters();
return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext,
argumentList != null ? argumentList.getExpressionTypes() : null, typeParameters.length > 0 ? typeParameters : null,
getLanguageLevel()) {
@Override
public boolean isVarargs() {
return varargs;
}
@NotNull
@Override
public PsiSubstitutor inferTypeArguments(@NotNull ParameterTypeInferencePolicy policy, boolean includeReturnConstraint) {
return inferTypeArguments(false); //includeReturnConstraint == vararg todo
return inferTypeArguments(varargs);
}
public PsiSubstitutor inferTypeArguments(boolean varargs) {
@@ -517,9 +528,6 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
}
if (!session.repeatInferencePhases(false)) {
if (method.isVarArgs() && !varargs) {
return inferTypeArguments(true);
}
return substitutor;
}
@@ -600,13 +608,14 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
mySignature = signature;
}
@Override
protected int getPertinentApplicabilityLevel(MethodCandidateInfo conflict) {
return conflict.isVarargs() ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY;
}
@Nullable
@Override
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts) {
return resolveConflict(conflicts, false);
}
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts, boolean varargs) {
if (mySignature == null) return null;
checkSameSignatures(conflicts);
@@ -627,6 +636,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
final PsiSubstitutor substitutor = conflict.getSubstitutor();
final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(substitutor).getParameterTypes();
final boolean varargs = ((MethodCandidateInfo)conflict).isVarargs();
if (varargs && (!psiMethod.isVarArgs() || myFunctionalMethodVarArgs)) continue;
if ((varargs || parameterTypes.length == signatureParameterTypes2.length) &&
@@ -655,19 +665,12 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
}
}
checkSpecifics(firstCandidates,
varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel);
checkSpecifics(secondCandidates,
varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel);
final int acceptedCount = firstCandidates.size() + secondCandidates.size();
if (acceptedCount == 1) {
if (resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY)) {
return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0);
}
if (!varargs) {
return resolveConflict(conflicts, true);
if (resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.VARARGS)) {
return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0);
}
conflicts.clear();
@@ -676,6 +679,17 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
return null;
}
private boolean resolveConflicts(List<CandidateInfo> firstCandidates, List<CandidateInfo> secondCandidates, int applicabilityLevel) {
checkApplicability(firstCandidates);
checkSpecifics(firstCandidates, applicabilityLevel, myLanguageLevel);
checkApplicability(secondCandidates);
checkSpecifics(secondCandidates, applicabilityLevel, myLanguageLevel);
return firstCandidates.size() + secondCandidates.size() == 1;
}
@Override
protected boolean nonComparable(CandidateInfo method, CandidateInfo conflict) {
if (method == conflict) return true;

View File

@@ -392,12 +392,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
@MethodCandidateInfo.ApplicabilityLevelConstant
private static int checkApplicability(List<CandidateInfo> conflicts) {
protected int checkApplicability(List<CandidateInfo> conflicts) {
@MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0;
boolean toFilter = false;
for (CandidateInfo conflict : conflicts) {
ProgressManager.checkCanceled();
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = ((MethodCandidateInfo)conflict).getPertinentApplicabilityLevel();
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict);
if (maxApplicabilityLevel > 0 && maxApplicabilityLevel != level) {
toFilter = true;
}
@@ -410,7 +410,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext();) {
ProgressManager.checkCanceled();
CandidateInfo info = iterator.next();
final int level = ((MethodCandidateInfo)info).getPertinentApplicabilityLevel();
final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info);
if (level < maxApplicabilityLevel) {
iterator.remove();
}
@@ -420,6 +420,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
return maxApplicabilityLevel;
}
protected int getPertinentApplicabilityLevel(MethodCandidateInfo conflict) {
return conflict.getPertinentApplicabilityLevel();
}
private static int getCheckAccessLevel(MethodCandidateInfo method){
boolean visible = method.isAccessible();
return visible ? 1 : 0;
@@ -570,6 +574,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
if (abstract2 && !abstract1) {
return Specifics.FIRST;
}
}
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && myArgumentsList instanceof PsiExpressionList && (typeParameters1.length == 0 || typeParameters2.length == 0)) {
@@ -661,6 +666,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
return raw1 ? Specifics.SECOND : Specifics.FIRST;
}
final boolean varargs1 = info1.isVarargs();
final boolean varargs2 = info2.isVarargs();
if (varargs1 ^ varargs2) {
return varargs1 ? Specifics.SECOND : Specifics.FIRST;
}
return Specifics.NEITHER;
}

View File

@@ -21,6 +21,7 @@ import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.PsiConflictResolver;
import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
@@ -54,13 +55,20 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
myPlace, myAccessClass, myCurrentFileContext, myPlaceFile) &&
!isShadowed(method);
if (isAccepted(method)) {
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible));
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, false));
if (acceptVarargs() && method.isVarArgs() && PsiUtil.isLanguageLevel8OrHigher(myPlace)) {
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, true));
}
myHasAccessibleStaticCorrectCandidate |= isAccessible && !staticProblem;
}
}
protected boolean acceptVarargs() {
return false;
}
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor,
final boolean staticProblem, final boolean accessible) {
final boolean staticProblem, final boolean accessible, final boolean varargs) {
final PsiExpressionList argumentList = getArgumentList();
return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext,
null, getTypeArguments(), getLanguageLevel()) {
@@ -68,6 +76,11 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
public PsiType[] getArgumentTypes() {
return getExpressionTypes(argumentList);
}
@Override
public boolean isVarargs() {
return varargs;
}
};
}

View File

@@ -63,4 +63,9 @@ public class MethodResolverProcessor extends MethodCandidatesProcessor {
public boolean execute(@NotNull PsiElement element, ResolveState state) {
return !myStopAcceptingCandidates && super.execute(element, state);
}
@Override
protected boolean acceptVarargs() {
return true;
}
}

View File

@@ -11,7 +11,7 @@ class Test {
}
static void foo2(final A<? extends Integer> bar) {
bar._<error descr="'_(capture<? extends java.lang.Integer>...)' in 'Test.A' cannot be applied to '(java.lang.String)'">("")</error>;
bar._<error descr="Cannot resolve method '_(java.lang.String)'">("")</error>;
}

View File

@@ -7,8 +7,8 @@ public class Sample {
<B> B bar(G<B> gb) {return null;}
void f(G1 g1) {
<error descr="Incompatible types. Found: 'B', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
<error descr="Incompatible types. Found: 'B', required: 'java.lang.String'">String l1 = bar(g1);</error>
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String l1 = bar(g1);</error>
Object o = bar(g1);
}
}

View File

@@ -0,0 +1,26 @@
class A<T> {
A(T... t) {
}
{
A<String> a = new A<>("a", "b");
foo(new A<>("", ""));
bar(new A<>("", ""));
bar(new A<>(get()));
//bar(new A<>(get( ), ""));
}
void foo(A<String> s) {}
<T> void bar(A<T> s) {}
<K> K get() {return null;}
<M> A<M> s(M... m) {
return null;
}
{
bar(s(get()));
bar(s(get(), ""));
}
}

View File

@@ -0,0 +1,8 @@
abstract class Im {
public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
public abstract <T> T createProxy(final Class<T> superClass, final Class... otherInterfaces);
void f(Class<?> implementation, Class rawType, boolean isInterface) {
createProxy(implementation, isInterface ? new Class[]{rawType} : EMPTY_CLASS_ARRAY);
}
}

View File

@@ -1,4 +1,4 @@
public class Test {
class Test {
interface II {
int _();

View File

@@ -31,6 +31,10 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testVarargs() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}

View File

@@ -176,6 +176,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void testVarargsOnNonPertinentPlace() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(false);
}