From 53d2ece5af560bcc95d26b2e1a55c68ea962fa1b Mon Sep 17 00:00:00 2001 From: m0rkeulv Date: Wed, 3 Apr 2024 20:41:59 +0200 Subject: [PATCH] added remapping of callie typeParameters to match static extension methods when evaluating callExpressions. --- .../semantics/HaxeCallExpressionUtil.java | 56 ++++++++++++++----- .../haxe/model/type/HaxeClassReference.java | 2 +- .../haxe/model/type/HaxeGenericResolver.java | 23 ++++++-- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/intellij/plugins/haxe/ide/annotator/semantics/HaxeCallExpressionUtil.java b/src/main/java/com/intellij/plugins/haxe/ide/annotator/semantics/HaxeCallExpressionUtil.java index 05d589132..ce3d5afa8 100644 --- a/src/main/java/com/intellij/plugins/haxe/ide/annotator/semantics/HaxeCallExpressionUtil.java +++ b/src/main/java/com/intellij/plugins/haxe/ide/annotator/semantics/HaxeCallExpressionUtil.java @@ -7,7 +7,6 @@ import com.intellij.plugins.haxe.model.*; import com.intellij.plugins.haxe.model.type.*; import com.intellij.plugins.haxe.model.type.resolver.ResolveSource; -import com.intellij.plugins.haxe.util.HaxeResolveUtil; import com.intellij.plugins.haxe.util.UsefulPsiTreeUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; @@ -104,6 +103,23 @@ public static CallExpressionValidation checkMethodCall(@NotNull HaxeCallExpressi int parameterCounter = 0; int argumentCounter = 0; + + + boolean isRestArg = false; + HaxeParameterModel parameter = null; + HaxeExpression argument; + + ResultHolder parameterType = null; + ResultHolder argumentType = null; + + HaxeGenericResolver argumentResolver = resolver.withoutUnknowns(); + // methods might have typeParameters with same name as a parent so we need to make sure we are not resolving parents type + // when resolving parameters + HaxeGenericResolver parameterResolver = resolver.withoutUnknowns(); + resolver.addAll(methodModel.getGenericResolver(resolver)); + + + if (validation.isStaticExtension) { // this might not work for literals, need to handle those in a different way if (methodExpression instanceof HaxeReferenceExpression) { @@ -114,23 +130,16 @@ public static CallExpressionValidation checkMethodCall(@NotNull HaxeCallExpressi validation.errors.add(new ErrorRecord(callExpression.getTextRange(), "Can not use extension method, wrong type")); return validation; } else { - // TODO check if literals, like "myString".SomeExtension() + // callie and extension methods might have different names for their TypeParameters, so we need to substitute values + SpecificHaxeClassReference paramClass = type.getClassType(); + SpecificHaxeClassReference callieClass = callieType.getClassType(); + HaxeGenericResolver remappedResolver = remapTypeParameters(paramClass, callieClass); + argumentResolver.addAll(remappedResolver); + resolver.addAll(remappedResolver); } } } - boolean isRestArg = false; - HaxeParameterModel parameter = null; - HaxeExpression argument; - - ResultHolder parameterType = null; - ResultHolder argumentType = null; - - HaxeGenericResolver argumentResolver = resolver.withoutUnknowns(); - // methods might have typeParameters with same name as a parent so we need to make sure we are not resolving parents type - // when resolving parameters - HaxeGenericResolver parameterResolver = resolver.withoutUnknowns(); - resolver.addAll(methodModel.getGenericResolver(resolver)); // checking arguments is a bit complicated, rest parameters allow "infinite" arguments and optional parameters can be "skipped" // so we only want to break the loop once we have either exhausted the arguments or parameter list. @@ -247,6 +256,25 @@ public static CallExpressionValidation checkMethodCall(@NotNull HaxeCallExpressi return validation; } + @NotNull + private static HaxeGenericResolver remapTypeParameters(SpecificHaxeClassReference paramClass, SpecificHaxeClassReference callieClass) { + HaxeGenericResolver remappedResolver = new HaxeGenericResolver(); + if (paramClass != null && callieClass != null ) { + // just going to do exact match remapping for now, unifying parameter type and callie type and then their typeParameters is probably quite complicated + if (paramClass.getHaxeClassReference().refersToSameClass(callieClass.getHaxeClassReference())) { + @NotNull ResultHolder[] specificsFromMethodArg = paramClass.getSpecifics(); + @NotNull ResultHolder[] specificsFromCallie = callieClass.getSpecifics(); + for (int i = 0; i < specificsFromMethodArg.length; i++) { + ResultHolder specArg = specificsFromMethodArg[i]; + ResultHolder specCallie = specificsFromCallie[i]; + if (specArg.isTypeParameter()) remappedResolver.add(specArg.getClassType().getClassName(), specCallie); + } + + } + } + return remappedResolver; + } + public static CallExpressionValidation checkFunctionCall(HaxeCallExpression callExpression, SpecificFunctionReference functionType) { CallExpressionValidation validation = new CallExpressionValidation(); validation.isFunction = true; diff --git a/src/main/java/com/intellij/plugins/haxe/model/type/HaxeClassReference.java b/src/main/java/com/intellij/plugins/haxe/model/type/HaxeClassReference.java index d4ff02cdc..959a584de 100644 --- a/src/main/java/com/intellij/plugins/haxe/model/type/HaxeClassReference.java +++ b/src/main/java/com/intellij/plugins/haxe/model/type/HaxeClassReference.java @@ -165,7 +165,7 @@ public boolean refersToSameClass(@Nullable HaxeClassReference other) { if (otherClass.getModel().isTypedef()) { HaxeGenericResolver resolver = HaxeGenericResolverUtil.generateResolverFromScopeParents(otherClass.getContext()); SpecificHaxeClassReference reference = otherClass.getModel().getUnderlyingClassReference(resolver); - if (reference != null) myClass = reference.getHaxeClass(); + if (reference != null) otherClass = reference.getHaxeClass(); } // Optimization diff --git a/src/main/java/com/intellij/plugins/haxe/model/type/HaxeGenericResolver.java b/src/main/java/com/intellij/plugins/haxe/model/type/HaxeGenericResolver.java index 8d969f3f1..f1c9e342b 100644 --- a/src/main/java/com/intellij/plugins/haxe/model/type/HaxeGenericResolver.java +++ b/src/main/java/com/intellij/plugins/haxe/model/type/HaxeGenericResolver.java @@ -598,10 +598,23 @@ public SpecificFunctionReference substituteTypeParamsWithAssignHintTypes(Specifi } public String toCacheString() { - String resolversAsString = resolvers.stream().map(entry -> entry.name() + ":" + entry.type().toPresentationString() + ":" + entry.resolveSource()) - .collect(Collectors.joining(",")); - String constrainsAsString = constaints.stream().map(entry -> entry.name() + ":" + entry.type().toPresentationString() + ":" + entry.resolveSource()) - .collect(Collectors.joining(",")); - return "resolvers:["+resolversAsString + "], constraints: [" + constrainsAsString+"]"; + if (isEmpty()) return "EMPTY"; + + StringBuilder builder = new StringBuilder(128); + + builder.append("resolvers:["); + for (ResolverEntry resolver : resolvers) { + builder.append(resolver.name()).append(":").append(resolver.type().toPresentationString()).append(":") + .append(resolver.resolveSource()); + } + + builder.append("], constraints: ["); + for (ResolverEntry entry : constaints) { + builder.append(entry.name()).append(":").append(entry.type().toPresentationString()).append(":").append(entry.resolveSource()); + } + builder.append("]"); + + return builder.toString(); + } }