As always, it is a silly programmer error. I forgot to resolve the other extra things I added (in addition to the transform method) in the AST modification. I have updated the code snippet to show that I am also resolving the constructor call I added. This works with the class generation now ... YAAAY!!!!!
That said, the original concern still exists. It feels like the type checking extension is good when - You have to redirect to a different method with the signature in the caller - You have to handle invalid assignments and other type checking errors But when you are trying to handle a missing method, and want to change the call arguments to match it (instead of routing to a different method that matches the args), it feels like we have to mess with the details of the argtypes assumed in the level above the type checking. If I had to add a few extra arguments to make it work, it feels like this is impossible because the argTypes is an array regards Saravanan On Mon, Sep 9, 2024 at 5:41 AM Saravanan Palanichamy <chava...@gmail.com> wrote: > Thank you jochen > > I have tried to comment on the code in the attachment. The problem is that > I am modifying the AST in the type checker and I am trying to make it > compatible with what comes after. I am sure I am doing something wrong > because the class generation fails with a stack traversal issue. I can deal > with the expression transformation and the like but my doubt is what is the > right way to work with the type checker when adding new elements to the AST > during type checking > > My specific problems are with these lines of code and that the overall > solution passed the type checking but did not pass class generation > > === > // Update argument types (this is what feels off to me, as if > I am hacking this. argument types is an array > // passed in from the type checker. It has the original arg > types and I am replacing it with the parameter > // types from the function I matched. Without this change, the > type checker complains that it is not able > // to verify the matching function) > argumentTypes.forEachIndexed { index, _ -> > paramTypes[index]?.also { argumentTypes[index] = it } > } > === > > > On Sun, Sep 8, 2024 at 11:54 PM Jochen Theodorou <blackd...@gmx.org> > wrote: > >> On 08.09.24 17:08, Saravanan Palanichamy wrote: >> [...] >> > override fun handleMissingMethod( >> > receiver: ClassNode, >> > name: String, >> > argumentList: ArgumentListExpression, >> > argumentTypes: Array<ClassNode>, >> > call: MethodCall >> > ): List<MethodNode> { >> > >> > // TODO: Add check for types as well and not just name and >> > number of params >> > val matchingMethod = receiver.methods.filter { >> > it.name <http://it.name> == name && argumentTypes.size == >> it.parameters.size >> > }.singleOrNull() ?: return emptyList() >> >> is this return here really intended? Won't it be a return for the >> method? But then again this code looks like Kotlin and I did not learn >> such details of that language... >> >> [...] >> > */// No way for me to update the expression (I cannot do a transform >> > because it will create a new expression that I have no way of setting >> back/* >> >> Maybe you need two steps, maybe an Expression transformer and maybe the >> type checking extension >> >> >> bye Jochen >> >
override fun handleMissingMethod( receiver: ClassNode, name: String, argumentList: ArgumentListExpression, argumentTypes: Array<ClassNode>, call: MethodCall ): List<MethodNode> { // I am matching name and number of args here, if the find is null, I'll return an empty list val matchingMethod = receiver.methods.filter { it.name == name && argumentTypes.size == it.parameters.size }.singleOrNull() ?: return emptyList() // If I found something, I will return that method return listOf(matchingMethod).also { // But I also need to update the call arguments to match the parameters of the method // So I get the parameter types val paramTypes = matchingMethod.parameters.map { it.type } // Update the argument list to match the method signature ArgumentListVisitor(typeCheckingVisitor.typeCheckingContext.source, paramTypes).also { call.arguments.visit(it) } // Update argument types (this is what feels off to me, as if I am hacking this. argument types is an array // passed in from the type checker. It has th original arg types and I am replacing it with the parameter // types from the function I matched. Without this change, the type checker complains that it is not able // to verify the matching function) argumentTypes.forEachIndexed { index, _ -> paramTypes[index]?.also { argumentTypes[index] = it } } } } private fun ClassNode.defaultConstructorExpression(): Expression = GeneralUtils.ctorX(this).apply { val defaultConstructor = declaredConstructors.single { it.parameters.isNullOrEmpty() } setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, defaultConstructor) } class ArgumentListVisitor( private val sourceUnit: SourceUnit, private val parameterTypes: List<ClassNode> ) : ClassCodeVisitorSupport() { override fun getSourceUnit() = sourceUnit override fun visitTupleExpression(expression: TupleExpression) { // parsing the tuple expression to wrap each argument with the transform function val modifiedArguments = expression.expressions.zip(parameterTypes) { arg, paramType -> GeneralUtils.callX( GeneralUtils.classX(REDEFINED_TYPES_NODE), "transform", GeneralUtils.args(arg ... + paramTypeReference.defaultConstructorExpression()) ).also { it.methodTarget = TRANSFORM_NODE it.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, TRANSFORM_NODE) it.inferred_type = paramType } } // Replacing all sub expressions inside the expression. we now have the transform method around each arg expression.expressions.also { it.clear() it.addAll(modifiedArguments) } } }