Skip to content

transparent implicit conversion macro not emitting the proper error #12429

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

Closed
soronpo opened this issue May 11, 2021 · 6 comments
Closed

transparent implicit conversion macro not emitting the proper error #12429

soronpo opened this issue May 11, 2021 · 6 comments

Comments

@soronpo
Copy link
Contributor

soronpo commented May 11, 2021

Among various inlining and macro usages, only transparent macro does not emit the error message reported inside.

Compiler version

3.0 master branch

Minimized code

Main code:

import scala.language.implicitConversions
inline def inlineError : Unit =
  compiletime.error("inlineError")
transparent inline def transparentInlineError : Unit =
  compiletime.error("transparentInlineError")

trait InlineConversion
object InlineConversion:
  inline implicit def fromInt(i : Int) : InlineConversion =
    compiletime.error("inlineConversionError")

trait TransparentInlineConversion
object TransparentInlineConversion:
  transparent inline implicit def fromInt(i : Int) : TransparentInlineConversion =
    compiletime.error("transparentInlineConversionError")

import scala.quoted.*

inline def macroError : Unit = ${macroErrorInternal}
def macroErrorInternal(using Quotes) : Expr[Unit] =
  import quotes.reflect.*
  report.error("macroError")
  '{}

transparent inline def transparentMacroError : Unit = ${transparentMacroErrorInternal}
def transparentMacroErrorInternal(using Quotes) : Expr[Unit] =
  import quotes.reflect.*
  report.error("transparentMacroError")
  '{}

trait MacroConversion
object MacroConversion:
  inline implicit def fromInt(i : Int) : MacroConversion = ${fromIntInternal}
  def fromIntInternal(using Quotes) : Expr[MacroConversion] =
    import quotes.reflect.*
    report.error("macroConversionError")
    '{???}
trait TransparentMacroConversion
object TransparentMacroConversion:
  transparent inline implicit def fromInt(i : Int) : TransparentMacroConversion = ${fromIntInternal}
  def fromIntInternal(using Quotes) : Expr[TransparentMacroConversion] =
    import quotes.reflect.*
    report.error("transparentMacroConversionError")
    '{???}

Test code:

object Test {
  inlineError //error: inlineError 
  transparentInlineError //error: transparentInlineError 
  val i1 : InlineConversion = 1 //error: inlineConversionError
  val i2 : TransparentInlineConversion = 2 //error: transparentInlineConversionError
  macroError //error: macroError 
  transparentMacroError //error: transparentMacroError 
  val i3 : MacroConversion = 3 //error: macroConversionError
  val i4 : TransparentMacroConversion = 4 //Found:    (4 : Int)  Required: TransparentMacroConversion                              
}

Output

transparentMacroError
  transparentMacroError

Found:    (4 : Int)
Required: TransparentMacroConversion
  val i4 : TransparentMacroConversion = 4

Expectation

The last error should be "transparentMacroConversionError", instead of the type mismatch error.
Note: the transparent macro errors are emitted first. Once commented out, we can see the other errors properly emitted.

@smarter
Copy link
Member

smarter commented May 11, 2021

I think this is a feature, not a bug as explained in #12409 (comment), if a transparent implicit fails with an error, it's not considered a valid implicit for the current implicit search (because we can't type it), the alternative would be to always consider such implicits as matching, but that could easily lead to ambiguous implicit errors when multiple transparent implicits are in scope.

@soronpo
Copy link
Contributor Author

soronpo commented May 11, 2021

What is the difference with a non-transparent inline implicit conversion or a transparent non-macro iniline conversion?

@soronpo
Copy link
Contributor Author

soronpo commented May 11, 2021

And even if we consider this a "feature", I think the proper behavior would be to look at the implicit candidates:

  • If we have only one candidate, then the error emitted by that candidate is presented.
  • If we have two or more candidates, and one has no error, than that candidate is accepted.
  • If we have two or more candidates and all have errors, that either construct a dedicated message or emit the type mismatch error.

@odersky
Copy link
Contributor

odersky commented May 12, 2021

By the rules of implicit search an implicit is applicable only if its application can be typed. For a transparent implicit, typing the application means typing the expansion. That explains the behavior, and I think that behavior is reasonable. So I also think there's nothing to fix here.

@soronpo
Copy link
Contributor Author

soronpo commented May 12, 2021

For a transparent implicit, typing the application means typing the expansion. That explains the behavior, and I think that behavior is reasonable

Then why does TransparentInlineConversion does display the error, in opposed to the transparent macro?

So I also think there's nothing to fix here.

This behavior is different than Scala 2 whitebox macros (meaning, that if I use c.abort(...) the error is emitted).

@soronpo
Copy link
Contributor Author

soronpo commented May 13, 2021

There is a simple workaround (that was suggested on a different issue by @nicolasstucki and works here), by changing

report.error("transparentMacroConversionError")
'{???}

to

'{compiletime.error("transparentMacroConversionError")}

Given this simple workaround, and given that the brains behind Scala think this is the proper behavior, I'm closing this issue.

@soronpo soronpo closed this as completed May 13, 2021
@som-snytt som-snytt closed this as not planned Won't fix, can't repro, duplicate, stale Feb 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants