https://kotlinlang.org logo
#arrow-meta
Title
# arrow-meta
t

Tim Abil

03/10/2022, 7:19 PM
Does arrow-meta provide any utils to resolve a type of
KtExpression
r

raulraja

03/10/2022, 8:09 PM
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

Tim Abil

03/10/2022, 8:17 PM
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

raulraja

03/10/2022, 8:23 PM
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

Tim Abil

03/10/2022, 8:27 PM
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

raulraja

03/10/2022, 8:33 PM
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

Tim Abil

03/10/2022, 8:38 PM
right right - what would i pass as
CompilerContext.(..)
check extension
ahh i got it
do i visit KtDeclarations the same way?
r

raulraja

03/10/2022, 9:32 PM
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

Tim Abil

03/10/2022, 9:44 PM
hmm but then i wouldnt need a
KtVisitor
at all right?
r

raulraja

03/10/2022, 9:45 PM
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

Tim Abil

03/10/2022, 9:46 PM
gotcha, i just have a bunch of logic implemented in the visitor and would prefer if i could resolve type when visitingCallExpression
r

raulraja

03/10/2022, 9:48 PM
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

Tim Abil

03/10/2022, 10:01 PM
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

raulraja

03/10/2022, 11:02 PM
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

Tim Abil

03/10/2022, 11:09 PM
expression.getResolvedCall(context)
is giving me null back perhaps my context reference is wrong
r

raulraja

03/10/2022, 11:10 PM
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

Tim Abil

03/10/2022, 11:15 PM
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
14 Views