Does arrow-meta provide any utils to resolve a typ...
# arrow-meta
t
Does arrow-meta provide any utils to resolve a type of
KtExpression
r
Hi @Tim Abil, The binding context is available as argument in most of the methods available in the Analysis extension. In meta those methods are
doAnalysis
analysisCompleted
. It’s also available in the declaration and expression checker context and you can find it inside the BindingTrace. If you have some code i may be able to point you as to how to get it in the place you are on now.
t
So im grabbing the
CompilerContext
from here and passing it down to my
KtVisitor
Then when i visit a
KtExpression
i assume i need to do something like this
r
that api and everything in the quotes package is gone from Arrow meta since the compiler is moving away from PSI to FIR and that API was gonna disappear after 1.8 on when FIR is stable. If you are in a different place like a callchecker you can get it with
context.trace.bindingContext
. What does you plugin try to perform?
t
Yeah im still using 1.5.31 since you guys are still in process of writing the new docs for FIR. I'm writing a Ktor plugin to generate a swagger spec and need to resolve a return type of
call.receive<T>()
to determine the endpoint's request body type.
the
validateFunction
basically looks for a fun with a specific annotation so i could
.accept
a visitor on it
r
instead of using quotes, I would write this in
arrow.meta.dsl.config.ConfigSyntax#callChecker
we are gonna relocate that function, it’s in the wrong package now, but that intercepts all calls.
Copy code
fun callChecker(
    check:
      CompilerContext.(
        resolvedCall: ResolvedCall<*>,
        reportOn: org.jetbrains.kotlin.com.intellij.psi.PsiElement,
        context: CallCheckerContext) -> Unit
  ): arrow.meta.phases.config.StorageComponentContainer
or
Copy code
fun declarationChecker(
    check:
      CompilerContext.(
        declaration: KtDeclaration,
        descriptor: DeclarationDescriptor,
        context: DeclarationCheckerContext) -> Unit
  ): arrow.meta.phases.config.StorageComponentContainer
Both of those context arguments have access to the binding trace
Copy code
interface CheckerContext {
    val trace: BindingTrace

    val languageVersionSettings: LanguageVersionSettings

    val deprecationResolver: DeprecationResolver

    val moduleDescriptor: ModuleDescriptor
}
you would use those instead of
namedFunction
if you intercept the right call you may not need the binding context at all. The reason being that the
descriptor: DesclarationDescriptor
is what you are probably trying to get out of the binding context.
t
right right - what would i pass as
CompilerContext.(..)
check extension
ahh i got it
do i visit KtDeclarations the same way?
r
try the callChecker first since you seem to be intercepting a call instead of analyzing the definition or member of a declaration
the call checker should actually intercept the precise call you are looking for.
t
hmm but then i wouldnt need a
KtVisitor
at all right?
r
no, you would just check the call you are intercepting is pointing to an annotated owner
that info will b inside the
resolvedCall
the call checker already traverses all calls so no need for a visitor unless you are back tracing or looking up or down a nested call.
t
gotcha, i just have a bunch of logic implemented in the visitor and would prefer if i could resolve type when visitingCallExpression
r
if you choose the declarationChecker path that will force you to implement the part where the call needs to be resolved, not a big deal but usually the most effitient for this case would be to use a call checker
calls have descriptor functions they are resolved to where you can extract annotation info and all the analysis knows about that call, including types etc.
FIR provides both call and declaration checkers, porting it later to FIR should be not too hard if you don’t depend much on the trace and binding context directly.
t
makes sense, so if do use the declarationChecker instead since that lets me invoke a custom Visitor. how would implement the call resolution in that case, perhaps there's an example can reference.
r
Once you reach a node that is a
call
you can get its
resolvedCall
with
org.jetbrains.kotlin.resolve.calls.util.CallUtilKt#getResolvedCall(org.jetbrains.kotlin.psi.KtElement, org.jetbrains.kotlin.resolve.BindingContext)
That is an ext fun available over
KtElement
and over
Call
t
expression.getResolvedCall(context)
is giving me null back perhaps my context reference is wrong
r
it may be that the call is not yet resolved at the point the declaration checker is running
try with a callchecker too to see if the call is intercepted with a resolved call. Or alternatively try extracting the binding context from the
ContextChecker
argument in the declaration checker instead of the one in the compiler context
t
yep im taking bindingContext from the
declarationCheckerContext
but that context is for the top level annotated function that i accept my Visitor to. Then the visitor visits the block of the annotated fun, iterates through the statements and visits another expression that im trying to resolve a type for.
so perhaps at that point its the wrong bindingContext
message has been deleted
message has been deleted
BindingContextUtils.getTypeNotNull(context, expression)
seems to be working. I figured the test code i was feeding couldnt actually compile because it was referencing external types that were missing imports in the test's input string
👍 1