Skip to content

Conversation

@tgodzik
Copy link
Contributor

@tgodzik tgodzik commented Mar 2, 2022

Fixes #1687

Related fix in Dotty: scala/scala3#14611

Most of the code is copied over from either the compiler or ScalaPResentationCompiler class.

@tgodzik tgodzik requested review from dos65 and tanishiking March 2, 2022 16:57
ctx: Context
): (Int, Int, List[SingleDenotation]) =
path match
case (tpd.UnApply(fun, implicits, patterns)) :: _ =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the main fix, we apply almost the same logic as for Apply in Signatures

Copy link
Member

Choose a reason for hiding this comment

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

Are we going to remove this pattern match once scala/scala3#14611 merged? In this case, can we wait for the next release that contains scala/scala3#14611 ?

Or leave this method for older Scala3 compilers? In this case, can we add a comment on why there's a kind of duplicated logic in metals and dotty?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we should leave it as a fallback, but I still need to work a bit on this.

val path =
Interactive
.pathTo(trees, pos)(using ctx)
.dropWhile {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is another place that actually got changes.

Copy link
Member

@tanishiking tanishiking left a comment

Choose a reason for hiding this comment

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

Metals part (SignatureHelpProvider.contribute) looks good to me :)
But I'm wondering maybe we should wait for the next release of Scala3 compiler 🤔

.dropWhile {
case _: tpd.Apply => false
case unapply: tpd.UnApply =>
// Don't show tuple unapply method
Copy link
Member

Choose a reason for hiding this comment

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

What happens if we show the tuple unapply method?

Copy link
Member

Choose a reason for hiding this comment

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

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just not really useful, since when writing tuples we are not really interested in signature help.

ctx: Context
): (Int, Int, List[SingleDenotation]) =
path match
case (tpd.UnApply(fun, implicits, patterns)) :: _ =>
Copy link
Member

Choose a reason for hiding this comment

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

Are we going to remove this pattern match once scala/scala3#14611 merged? In this case, can we wait for the next release that contains scala/scala3#14611 ?

Or leave this method for older Scala3 compilers? In this case, can we add a comment on why there's a kind of duplicated logic in metals and dotty?

@tgodzik tgodzik force-pushed the unapply-signature-help branch from 3c94fa1 to 4f518ea Compare March 4, 2022 16:50
@tgodzik tgodzik force-pushed the unapply-signature-help branch from 4f518ea to eb3bdcd Compare March 4, 2022 16:52
|""".stripMargin,
compat = Map(
"3" ->
"""|Two[T](a: T, b: T)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I reworked the unapply signature for case classes to show the actual case classes. It's a bit different than in case of Scala 2, but I think this is a bit better since def unapply(a: T, b: T): Two[T] does not exist. The alternative would be to show the parameters alone.

@tgodzik tgodzik requested review from kpodsiad and tanishiking March 4, 2022 16:53
@tgodzik
Copy link
Contributor Author

tgodzik commented Mar 4, 2022

The failures are related to my tinkering in the compiler.

Copy link
Member

@tanishiking tanishiking left a comment

Choose a reason for hiding this comment

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

Diff seems good! And showing the actual case classes for unapply signature of case classes is a great idea 👍

I just left some questions (as it seems a bit tricky for me), it could be helpful if you can leave some code comments answering my questions. (those comments may help future us to comprehend the program around here :)

documentation.foreach(info.setDocumentation(_))
info

private def signatureToSignatureInformation(
Copy link
Member

Choose a reason for hiding this comment

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

[note] Basically there're no change In paramsToParameterInformation and signatureToSignatureInformation


val funSymbol = fun.symbol
val retType = funSymbol.info.finalResultType
val isSomeMatch = funSymbol.owner.companionClass == defn.SomeClass
Copy link
Member

Choose a reason for hiding this comment

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

I assume this will be true for something like case Some(@@), am I right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeas, that's the special case I wanted to handle.

val retType = funSymbol.info.finalResultType
val isSomeMatch = funSymbol.owner.companionClass == defn.SomeClass
val isExplicitUnapply =
!isSomeMatch && retType.typeSymbol == defn.OptionClass
Copy link
Member

Choose a reason for hiding this comment

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

isExplicitUnapply will be true when we explicitly call unapply method like Foo.unapply(@@)


I thought isExplicitUnapply will always true, for pattern match over case classes

case class Foo(a: Int)

x match {
  // here I thought `fun` will be an `unapply` method of `Foo`
  // whose `finalResultType` is Option[Foo]
  // and it's always true for all case classes.
  case Foo(@@) 
}

Against my assumption, is retType gonna be Foo (instead of Option[Foo])?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isExplicitUnapply will be true when we explicitly call unapply method like Foo.unapply(@@)

It might be, but we will be at an Apply node, so the code will not be invoked.

Copy link
Member

Choose a reason for hiding this comment

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

Auch, I got it! isExplicitUnapply = true means unapply method is explicitly defined, not explicitly called

!isSomeMatch && retType.typeSymbol == defn.OptionClass
val paramIndex =
if isExplicitUnapply then implicitsBefore
else defaultParamIndex
Copy link
Member

Choose a reason for hiding this comment

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

Why we use implicitsBefore for Foo.unapply(@@) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can have in Scala 3 def unapply(using A)(value: Value) = ??? so we need to highlight the first parameter after the using params.

Copy link
Member

Choose a reason for hiding this comment

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

I got it! Okay, so implicitsBefore means (the number of) "implicit parameters before" (actual parameter(?) of the constructor) 👍

Copy link
Member

@tanishiking tanishiking left a comment

Choose a reason for hiding this comment

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

Again it's LGTM. This one is what I'd been longing for in Scala3. I look forward to using this feature!

Copy link
Member

@dos65 dos65 left a comment

Choose a reason for hiding this comment

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

Cool! LGTM!

| }
|}
|""".stripMargin,
"""|unapply(implicit x$1: String)(implicit x$2: Boolean)(a: Int): Option[(Int, Int)]
Copy link
Member

Choose a reason for hiding this comment

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

For scala 3 shouldn't implicit be called using?

Copy link
Member

Choose a reason for hiding this comment

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

can be fixed with #3707 :)

@tgodzik
Copy link
Contributor Author

tgodzik commented May 13, 2022

Closing this for now, we might get help from the compiler team for this 🎉

@tgodzik tgodzik closed this May 13, 2022
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.

No signature help inside pattern match for Scala 3

4 participants