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)
        }
    }
}

Reply via email to