Skip to content

Commit

Permalink
type inference checking for class type parameters in call expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
m0rkeulv committed Apr 9, 2024
1 parent 47bc923 commit abeede4
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,13 @@ private static HaxeGenericResolver findTypeParametersToInherit(SpecificTypeRefer

findTypeParametersToInherit(parameterReturnType.getType(), argumentReturnType.getType(), resolver, map);
}
if (parameter.isTypeParameter() && !argument.isTypeParameter() && !argument.isUnknown()) {
if (parameter instanceof SpecificHaxeClassReference classReference) {
if (classReference.getClassName() != null) {
resolver.add(classReference.getClassName(), argument.createHolder(), ResolveSource.ARGUMENT_TYPE);
}
}
}


return resolver;
Expand Down Expand Up @@ -1072,6 +1079,7 @@ public static class CallExpressionValidation {
Map<Integer, Integer> argumentToParameterIndex = new HashMap<>();
Map<Integer, ResultHolder> argumentIndexToType = new HashMap<>();
Map<Integer, ResultHolder> ParameterIndexToType = new HashMap<>();
ResultHolder returnType;

List<ErrorRecord> errors = new ArrayList<>();
List<WarningRecord> warnings = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,20 +572,39 @@ private static ResultHolder checkSearchResult(HaxeExpressionEvaluatorContext con
if (callExpression.getExpression() instanceof HaxeReference callExpressionReference) {
final PsiElement resolved = callExpressionReference.resolve();
HaxeCallExpressionList list = callExpression.getExpressionList();
int index = -1;
if (list != null) index = list.getExpressionList().indexOf(referenceExpression);
if (index > -1 && resolved instanceof HaxeMethod method) {
HaxeCallExpressionUtil.CallExpressionValidation validation = HaxeCallExpressionUtil.checkMethodCall(callExpression, method);
if (validation.isStaticExtension()) index++;
ResultHolder paramType = validation.getParameterIndexToType().getOrDefault(index, null);
if (paramType != null) return paramType;
// check if reference used as parameter
ResultHolder paramType = findUsageAsParameterInFunctionCall(referenceExpression, callExpression, list, resolved);
if (paramType != null) return paramType;
// check if our reference is the callie
final HaxeReference leftReference = PsiTreeUtil.getChildOfType(callExpression.getExpression(), HaxeReference.class);
if (leftReference == reference) {
if (resolved instanceof HaxeMethod method ) {
HaxeCallExpressionUtil.CallExpressionValidation validation = HaxeCallExpressionUtil.checkMethodCall(callExpression, method);
ResultHolder hintResolved = validation.getResolver().resolve(hint);
if (hintResolved != null && !hintResolved.isUnknown()) return hintResolved;
}
}
}
}
}
return null;
}

private static @Nullable ResultHolder findUsageAsParameterInFunctionCall(HaxeReferenceExpression referenceExpression,
HaxeCallExpression callExpression,
HaxeCallExpressionList list,
PsiElement resolved) {
int index = -1;
if (list != null) index = list.getExpressionList().indexOf(referenceExpression);
if (index > -1 && resolved instanceof HaxeMethod method) {
HaxeCallExpressionUtil.CallExpressionValidation validation = HaxeCallExpressionUtil.checkMethodCall(callExpression, method);
if (validation.isStaticExtension()) index++;
ResultHolder paramType = validation.getParameterIndexToType().getOrDefault(index, null);
if (paramType != null) return paramType;
}
return null;
}

@NotNull
public static ResultHolder searchReferencesForTypeParameters(final HaxePsiField field,
final HaxeExpressionEvaluatorContext context,
Expand Down Expand Up @@ -629,7 +648,10 @@ public static ResultHolder searchReferencesForTypeParameters(final HaxePsiField

HaxeGenericResolver resolverFromCallExpression = validation.getResolver();
if (resolverFromCallExpression != null) {
ResultHolder resolve = resolverFromCallExpression.resolve(resultHolder);
// removing any typeParameters that are local to the method (we only want type parameters that are class specific)
resolverFromCallExpression.removeAll(methodModel.getGenericResolver(null).names());
// bit of a hack to get rid of any unknowns
ResultHolder resolve = resolverFromCallExpression.resolve(resultHolder.getClassType().replaceUnknownsWithTypeParameter());
if (resolve != null && !resolve.isUnknown()) {
return resolve;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ static ResultHolder handleLocalVarDeclaration(
if (!resolveInProgress.contains(element)) {
try {
resolveInProgress.add(element);
ResultHolder searchResult = searchReferencesForType(element, context, resolver, null);
ResultHolder searchResult = searchReferencesForType(element, context, resolver, null, result);
// if we got a type we should check that we find the correct match (avoid replacing a class with an interface match etc.)
if (result == null || searchResult.getType().isSameType(result.getType())) {
result = searchResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,4 +631,11 @@ public String toCacheString() {
return builder.toString();

}

public void removeAll(String[] names) {
for (String name : names) {
resolvers.removeIf(entry -> entry.name().equals(name));
constaints.removeIf(entry -> entry.name().equals(name));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,21 @@ public ResultHolder access(String name, HaxeExpressionEvaluatorContext context,
return null;
}

public ResultHolder replaceUnknownsWithTypeParameter() {
if (getHaxeClassModel() == null) return this.createHolder();
List<HaxeGenericParamModel> params = getHaxeClassModel().getGenericParams();
ResultHolder[] newSpecifics = new ResultHolder[params.size()];
for (HaxeGenericParamModel param : params) {
int index = param.getIndex();
if (specifics[index].isUnknown()) {
HaxeClassReference reference = new HaxeClassReference(param.getName(), param.getPsi(), true);
newSpecifics[index] = SpecificHaxeClassReference.withoutGenerics(reference).createHolder();
}else {
newSpecifics[index] = specifics[index];
}
}
return new ResultHolder(SpecificHaxeClassReference.withGenerics(classReference, newSpecifics));
}


public enum Compatibility {
Expand Down

0 comments on commit abeede4

Please sign in to comment.