Skip to content

Quoted match on an exported definition? (matching the "original" definition) #12959

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

Open
deusaquilus opened this issue Jun 27, 2021 · 7 comments
Assignees
Labels
area:metaprogramming:quotes Issues related to quotes and splices itype:enhancement

Comments

@deusaquilus
Copy link
Contributor

Compiler version

Latest Nightly: scala-3.0.2-RC1-bin-20210626-f33bc8d-NIGHTLY

Minimized code

Create a global function in a namespace (e.g. Dsl). Then export it:

package io.getquill.mytest

object Dsl:
  def stuff: String = ???

export Dsl._

Then make a quoted-match clause to match it:

object ParseMacro:
  inline def parse(inline any: Any): Unit = ${ parseImpl('any) }
  def parseImpl(any: Expr[Any])(using Quotes): Expr[Unit] =
    import quotes.reflect._
    any match
      case '{ Dsl.stuff } => println("Matched!")
      case _ => println("Did not match")
    '{ () }

Then use the macro to match it based on the export:

import mytest._
ParseMacro.parse(stuff)

It will not match.

Output

The clause does not match i.e. Did not match is printed.

Expectation

The clause should match the exported symbol.

Repo

Example code can be found here:
https://github.com/deusaquilus/export_match_issue

@deusaquilus
Copy link
Contributor Author

deusaquilus commented Jun 27, 2021

Note that this is a serious issue. If you have dozens of functions defined in the Dsl object and want them to be exported up to the package-level, you literally have to repeat every single quoted-match clause twice. I.e:

For this:

object Dsl:
  def stuff: String = ???
  def otherStuff: String = ???
  def otherOtherStuff: String = ???

Need to do this:

    any match
      case '{ Dsl.stuff } => println("Matched!")
      case '{ Dsl.otherStuff } => println("Matched!")
      case '{ Dsl.otherOtherStuff } => println("Matched!")
      case '{ stuff } => println("Matched!")
      case '{ otherStuff } => println("Matched!")
      case '{ otherOtherStuff } => println("Matched!")

@bishabosha
Copy link
Member

bishabosha commented Jun 27, 2021

exports create forwarder methods, so stuff is simply unrelated to Dsl.stuff, just like if you declared two methods in different namespaces that share the same name. So I am recording this as intended behaviour.

@deusaquilus
Copy link
Contributor Author

@bishabosha However you choose to classify it, this is still a significant problem. It basically means that quoted-dsls can never be exported unless the writer of the parser is willing to reproduce all of the match-clauses over and over again (let alone the fact that this behavior is extremely unintuitive).

@bishabosha bishabosha changed the title Exported Symbols not matched from the original path Quoted match on an exported definition? Jun 28, 2021
@bishabosha
Copy link
Member

bishabosha commented Jun 28, 2021

We already have some de-virtualisation for overridden methods in quotes, so it could be worth exploring (following exports to their original definition) @nicolasstucki ?

currently there is no efficient compiler machinery for this but it is possible to implement your own reverse map for exported definitions by checking for a symbol ref, where that ref has the Exported flag, and then you follow the return type of that definition, or its rhs, to find where that export was defined in. Theres an example of using TastyInspector to do this in scaladoc: https://github.com/lampepfl/dotty/blob/f33bc8df9bbdabb921fe70b0d136cb3fd4f25355/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala#L137

@bishabosha bishabosha changed the title Quoted match on an exported definition? Quoted match on an exported definition? (support matching the "original" definition) Jun 28, 2021
@bishabosha bishabosha changed the title Quoted match on an exported definition? (support matching the "original" definition) Quoted match on an exported definition? (matching the "original" definition) Jun 28, 2021
@dwijnand dwijnand added this to the 3.1.0 milestone Jun 30, 2021
@dwijnand dwijnand added the needs-minor-release This PR cannot be merged until the next minor release label Jun 30, 2021
@odersky
Copy link
Contributor

odersky commented Jun 30, 2021

I think that touches quoting more than exports. Should patterns in quotes be able to see through aliases? I am not sure about this.

@odersky odersky assigned nicolasstucki and unassigned odersky Jun 30, 2021
@deusaquilus
Copy link
Contributor Author

@odersky If quoted patterns won't see through aliases, it essentially makes export a huge pain for qDSL writers since users might use the non-exported version of the keyword. What's a case where you won't want a aliased/non-aliased term to have same matching behavior?

Heh, maybe there should be a transparent export 😋

@dwijnand
Copy link
Member

dwijnand commented Jul 1, 2021

(Oops, I meant to assign/label #12949 as fixed in the next minor release when Martin's #12979 is merged.)

@dwijnand dwijnand removed the needs-minor-release This PR cannot be merged until the next minor release label Jul 1, 2021
@dwijnand dwijnand removed this from the 3.1.0 milestone Jul 1, 2021
@nicolasstucki nicolasstucki added area:metaprogramming:reflection Issues related to the quotes reflection API area:metaprogramming:quotes Issues related to quotes and splices and removed area:metaprogramming area:metaprogramming:reflection Issues related to the quotes reflection API labels Jun 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:metaprogramming:quotes Issues related to quotes and splices itype:enhancement
Projects
None yet
Development

No branches or pull requests

5 participants