Skip to content

Commit

Permalink
fix: map name position to desugared version of named context bound (#…
Browse files Browse the repository at this point in the history
…22374)

resolves: #22335
This PR changes the positions so context bound name position is
correctly mapped in the desugaring:
```scala
def aa[T : Numeric as num]() = ??? // original code
def aa[T >: Nothing <: Any]()(using num: Numeric[T]): Nothing = ??? // desugared code, where position of `num` points to `num` in the original code
```
This also affects the cases where context bound is not named. The
definition position of `evidence$0` changed:
```scala
def aa[T : Numeric]() = ??? // original code
def aa[T >: Nothing <: Any]()(using evidence$0: Numeric[T]): Nothing = ??? // desugared code
// previously position of evidence$0 in original code
def aa[T : <<>>Numeric]() = ???
// after this PR
def aa[T : Numeric<<>>]() = ???
```
Which I think makes sense since if the was a name it would go after the
context bound
  • Loading branch information
tgodzik authored Jan 20, 2025
2 parents 08442e8 + 942d752 commit db23c08
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 12 deletions.
12 changes: 7 additions & 5 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -272,18 +272,20 @@ object desugar {
case ContextBounds(tbounds, ctxbounds) =>
val isMember = evidenceFlags.isAllOf(DeferredGivenFlags)
for bound <- ctxbounds do
val evidenceName = bound match
val (evidenceName, spanPoint) = bound match
case ContextBoundTypeTree(_, _, ownName) if !ownName.isEmpty =>
ownName // if there is an explicitly given name, use it.
val realName = ownName.stripModuleClassSuffix.lastPart
(ownName, bound.span.end - realName.length) // if there is an explicitly given name, use it.
case _ =>
if Config.nameSingleContextBounds
&& !isMember
&& ctxbounds.tail.isEmpty
&& Feature.enabled(Feature.modularity)
then tdef.name.toTermName
else freshName(bound)
then (tdef.name.toTermName, bound.span.point)
else (freshName(bound), bound.span.point)
evidenceNames += evidenceName
val evidenceParam = ValDef(evidenceName, bound, EmptyTree).withFlags(evidenceFlags)
val evidenceParam =
ValDef(evidenceName, bound, EmptyTree).withFlags(evidenceFlags).withSpan(bound.span.withPoint(spanPoint))
evidenceParam.pushAttachment(ContextBoundParam, ())
evidenceBuf += evidenceParam
tbounds
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2265,7 +2265,8 @@ object Parsers {
in.nextToken()
ident()
else EmptyTermName
ContextBoundTypeTree(t, pname, ownName)
val newSpan = t.span.withPoint(t.span.end).withEnd(in.lastOffset)
ContextBoundTypeTree(t, pname, ownName).withSpan(newSpan)

/** ContextBounds ::= ContextBound [`:` ContextBounds]
* | `{` ContextBound {`,` ContextBound} `}`
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2466,7 +2466,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
def typedContextBoundTypeTree(tree: untpd.ContextBoundTypeTree)(using Context): Tree =
val tycon = typedType(tree.tycon)
def spliced(tree: Tree) = untpd.TypedSplice(tree)
val tparam = untpd.Ident(tree.paramName).withSpan(tree.span)
val tparam = untpd.Ident(tree.paramName).withSpan(tree.span.withEnd(tree.span.point))
if tycon.tpe.typeParams.nonEmpty then
val tycon0 = tycon.withType(tycon.tpe.etaCollapse)
typed(untpd.AppliedTypeTree(spliced(tycon0), tparam :: Nil))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,27 @@ class HoverDefnSuite extends BaseHoverSuite:
|""".stripMargin,
"val foo: Int".hover
)

@Test def `i22335` =
check(
"""|def fromInt[T: Numeric as n@@um](t: Int): T = num.fromInt(t)
|""".stripMargin,
"""|num: Numeric[T]
|""".stripMargin.hover
)

@Test def `i22335-2` =
check(
"""|def showMax[X : {Numeric as nu@@m, Ordered as ord}](x: X, y: X): String = ???
|""".stripMargin,
"""|num: Numeric[X]
|""".stripMargin.hover
)

@Test def `i22335-3` =
check(
"""|def showMax[X : {Nu@@meric as num, Ordered as ord}](x: X, y: X): String = ???
|""".stripMargin,
"""|type Numeric: Numeric
|""".stripMargin.hover
)
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite {
| import quotes.reflect.*
| Type.of[T] match
| case '[f] =>
| val fr/*: TypeRepr<<scala/quoted/Quotes#reflectModule#TypeRepr#>>*/ = TypeRepr.of[T]/*(using evidence$1<<(3:23)>>)*/
| val fr/*: TypeRepr<<scala/quoted/Quotes#reflectModule#TypeRepr#>>*/ = TypeRepr.of[T]/*(using evidence$1<<(3:27)>>)*/
|""".stripMargin
)

Expand Down
2 changes: 1 addition & 1 deletion tests/pos/i20901/Foo.tastycheck
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Trees (98 bytes, starting from <elided base index>):
96: STRINGconst 32 [<elided source file name>]
98:

Positions (73 bytes, starting from <elided base index>):
Positions (75 bytes, starting from <elided base index>):
lines: 7
line sizes:
38, 0, 23, 0, 10, 41, 0
Expand Down
2 changes: 1 addition & 1 deletion tests/semanticdb/expect/Synthetic.expect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Synthetic/*<-example::Synthetic#*/ {
null.asInstanceOf/*->scala::Any#asInstanceOf().*/[Int/*->scala::Int#*/ => Int/*->scala::Int#*/](2)
}

class J/*<-example::Synthetic#J#*/[T/*<-example::Synthetic#J#[T]*/: /*<-example::Synthetic#J#evidence$1.*/Manifest/*->scala::Predef.Manifest#*//*->example::Synthetic#J#[T]*/] { val arr/*<-example::Synthetic#J#arr.*/ = Array/*->scala::Array.*/.empty/*->scala::Array.empty().*/[T/*->example::Synthetic#J#[T]*/] }
class J/*<-example::Synthetic#J#*/[T/*<-example::Synthetic#J#[T]*/: Manifest/*->scala::Predef.Manifest#*//*->example::Synthetic#J#[T]*//*<-example::Synthetic#J#evidence$1.*/] { val arr/*<-example::Synthetic#J#arr.*/ = Array/*->scala::Array.*/.empty/*->scala::Array.empty().*/[T/*->example::Synthetic#J#[T]*/] }

class F/*<-example::Synthetic#F#*/
implicit val ordering/*<-example::Synthetic#ordering.*/: Ordering/*->scala::package.Ordering#*/[F/*->example::Synthetic#F#*/] = ???/*->scala::Predef.`???`().*/
Expand Down
4 changes: 2 additions & 2 deletions tests/semanticdb/metac.expect
Original file line number Diff line number Diff line change
Expand Up @@ -2734,7 +2734,7 @@ Occurrences:
[17:9..17:10): U <- example/Methods#m7().[U]
[17:12..17:20): Ordering -> scala/math/Ordering#
[17:12..17:20): Ordering -> example/Methods#m7().[U]
[17:12..17:12): <- example/Methods#m7().(evidence$1)
[17:20..17:20): <- example/Methods#m7().(evidence$1)
[17:22..17:23): c <- example/Methods#m7().(c)
[17:25..17:32): Methods -> example/Methods#
[17:33..17:34): T -> example/Methods#[T]
Expand Down Expand Up @@ -3668,9 +3668,9 @@ Occurrences:
[32:8..32:9): J <- example/Synthetic#J#
[32:9..32:9): <- example/Synthetic#J#`<init>`().
[32:10..32:11): T <- example/Synthetic#J#[T]
[32:13..32:13): <- example/Synthetic#J#evidence$1.
[32:13..32:21): Manifest -> scala/Predef.Manifest#
[32:13..32:21): Manifest -> example/Synthetic#J#[T]
[32:21..32:21): <- example/Synthetic#J#evidence$1.
[32:29..32:32): arr <- example/Synthetic#J#arr.
[32:35..32:40): Array -> scala/Array.
[32:41..32:46): empty -> scala/Array.empty().
Expand Down

0 comments on commit db23c08

Please sign in to comment.