Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Few comments regarding the FIR and BIR apis #11

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

raulraja
Copy link
Member

@raulraja raulraja commented Jun 9, 2022

DO NOT MERGE.

This PR contains a few comments regarding our experience using the Frontend and Backend IR to build compiler plugins.

All comments start with (FIR API review and comments), code related changes can be ignored.

@raulraja raulraja marked this pull request as draft June 9, 2022 08:04
* can be efficient to avoid traversing the tree searching for declarations.
* In this case though we are forcing the user to always use or look for annotated declarations.
*
* Ideally predicates are more expressive than just searching for annotations and allow the user to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's impossible, because it won't work in IDE, because it will require resolution of the whole module to TYPES stage, which will be very slow

/**
* (FIR API review and comments)
*
* The `+` operator makes for a nice API in simple plugins whose extensions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it may be not the best syntax. I just thought at some point that it looks pretty nice, but I'm not sure about it right now

* only take a `session` as single argument but becomes more unreadable when like in our
* case we need to pass extra arguments to the constructor.
*
* An alternative could be that our `proofCache` argument becomes a session component.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, session components are not available in backend. But you can use something like that:

class ProofCache

class ProofCacheStorage(session: FirSession, val proofCache: ProofCache) : FirExtensionSessionComponent(session)

private val FirSession.proofCacheStorage: ProofCacheStorage by FirSession.sessionComponentAccessor()
val FirSession.proofCache: ProofCache
    get() = proofCacheStorage.proofCache

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!, we will try to refactor to that

*
* # what's the plugin key for?
*
* We have used this one across the frontend to set the `origin`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keys can be used for passing some information from FIR to IR. We save a plugin key in IrDeclarationOrigin, so you can create it in frontend generator and then read it from the IR for this declaration

We're considering different approaches for such data translation (e.g. by introducing declaration attributes for IR declarations), but for now this is the only way except some external service

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense and this clarifies it.

.apply {
/**
* (FIR API review and comments)
* We have run into runtime errors a few time when compiling because some of the properties
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a price for builder functions instead of constructor calls. There are two things which we possibly can do with it:

  1. Write proper documentation
  2. Introduce safe builders feature (actually, I want to do it for four years, because it was the topic of my master degree, but the most optimistic estimate I can give is release of FIR, which mostl likely will be 1.10)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are very interested in safe builders as well, if there is anything we can do to help there even if in the future let us know. :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design for them was done a long time ago. So now we need to actualize it and implement it in the FIR.
The thing is that we don't want to do it in both frontends

* FIR call resolver and similar services.
* This was done so that we could resolve a fir call given a list of
* provider candidates. At the time we are writing this FIR does not
* expose any public service or hook for call resolution.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeo, it won't be possible to modify existing resolution. But I think we can simplify API for custom calling of FirCallResolver. Please create a feature request for it in the YT

/**
* (FIR API review and comments)
*
* Looked around for an api that would allow me to generate a call given a
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have some helpers to simplify generating FIR and IR as part of the compiler API. I faced with such boilerplate issues myself and I don't like it.

You can create such helpers by yourself and send them as PR, it would be very helpful

* allow to call any of the `referenceFunction` or similar methods
* available in the plugin context.
*
* Referencing functions and symbols with the `symbolTable` requires building
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a known issue, I'll work on it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

/**
* (FIR API review and comments)
*
* # Repeated common FIR properties such as `name` not under common interface
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had FirNamedDeclaration before, but then we decided to discard this interface, because there is no actual point in it. Named declarations don't have anything in common except the name. You never work with a collection of just declarations, you need to split them into class like declarations and class like declarations and treat them differently. I don't see any usecase where logic in plugin depends only on the name of declaration, but don't' distinguish classes and functions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, this plugin generically depends on callable declarations having a name for rendering providers.
This plugin support these different kinds of providers.

val foo: Foo = Foo()
fun foo(): Foo = Foo()
class Foo
object Foo

All of them have a name, but it's not a big deal, we thought it made sense because others like Type Parameters containers have their own interface type.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class and object are not callable declarations

* We'd like in this case `name` and others to appear in a shared
* interface or place like `FirNamedDeclaration` to avoid functions
* like this one.
*/
val declarationName: Name
get() = when (val decl = declaration) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW this implementation is incorrect

val FirDeclaration.declarationName: Name
    get() = when (this) {
        is FirCallableDeclaration -> symbol.name
        is FirClassLikeDeclaration -> symbol.name
        is FirTypeParameter -> name
        else -> error("Unsupported declaration ${this.renderWithType()}")
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants