Skip to content

Commit 409d13a

Browse files
authored
Fix goto-def on exported forwarders (#19494)
2 parents 62f0324 + 0ee03ef commit 409d13a

File tree

7 files changed

+115
-21
lines changed

7 files changed

+115
-21
lines changed

Diff for: compiler/src/dotty/tools/dotc/ast/tpd.scala

+5
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11421142
buf.toList
11431143
}
11441144

1145+
def collectSubTrees[A](f: PartialFunction[Tree, A])(using Context): List[A] =
1146+
val buf = mutable.ListBuffer[A]()
1147+
foreachSubTree(f.runWith(buf += _)(_))
1148+
buf.toList
1149+
11451150
/** Set this tree as the `defTree` of its symbol and return this tree */
11461151
def setDefTree(using Context): ThisTree = {
11471152
val sym = tree.symbol

Diff for: compiler/src/dotty/tools/dotc/core/Flags.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ object Flags {
363363
val (Enum @ _, EnumVal @ _, _) = newFlags(40, "enum")
364364

365365
/** An export forwarder */
366-
val (Exported @ _, _, _) = newFlags(41, "exported")
366+
val (Exported @ _, ExportedTerm @ _, ExportedType @ _) = newFlags(41, "exported")
367367

368368
/** Labeled with `erased` modifier (erased value or class) */
369369
val (Erased @ _, _, _) = newFlags(42, "erased")

Diff for: compiler/src/dotty/tools/dotc/core/Symbols.scala

+15-4
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import DenotTransformers.*
1919
import StdNames.*
2020
import NameOps.*
2121
import NameKinds.LazyImplicitName
22-
import ast.tpd
23-
import tpd.{Tree, TreeProvider, TreeOps}
24-
import ast.TreeTypeMap
22+
import ast.*, tpd.*
2523
import Constants.Constant
2624
import Variances.Variance
2725
import reporting.Message
@@ -325,13 +323,26 @@ object Symbols extends SymUtils {
325323

326324
/** A symbol related to `sym` that is defined in source code.
327325
*
328-
* @see enclosingSourceSymbols
326+
* @see [[interactive.Interactive.enclosingSourceSymbols]]
329327
*/
330328
@annotation.tailrec final def sourceSymbol(using Context): Symbol =
331329
if (!denot.exists)
332330
this
333331
else if (denot.is(ModuleVal))
334332
this.moduleClass.sourceSymbol // The module val always has a zero-extent position
333+
else if denot.is(ExportedType) then
334+
denot.info.dropAlias.finalResultType.typeConstructor match
335+
case tp: NamedType => tp.symbol.sourceSymbol
336+
case _ => this
337+
else if denot.is(ExportedTerm) then
338+
val root = denot.maybeOwner match
339+
case cls: ClassSymbol => cls.rootTreeContaining(name.toString)
340+
case _ => EmptyTree
341+
val targets = root.collectSubTrees:
342+
case tree: DefDef if tree.symbol == denot.symbol => methPart(tree.rhs).tpe
343+
targets.match
344+
case (tp: NamedType) :: _ => tp.symbol.sourceSymbol
345+
case _ => this
335346
else if (denot.is(Synthetic)) {
336347
val linked = denot.linkedClass
337348
if (linked.exists && !linked.is(Synthetic))

Diff for: compiler/src/dotty/tools/dotc/interactive/SourceTree.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ case class SourceTree(tree: tpd.Import | tpd.NameTree, source: SourceFile) {
4242
(treeSpan.end - nameLength, treeSpan.end)
4343
Span(start, end, start)
4444
}
45-
source.atSpan(position)
45+
// Don't widen the span, only narrow.
46+
// E.g. The star in a wildcard export is 1 character,
47+
// and that is the span of the type alias that results from it
48+
// but the name may very well be larger, which we don't want.
49+
val span1 = if treeSpan.contains(position) then position else treeSpan
50+
source.atSpan(span1)
4651
}
4752
case _ =>
4853
NoSourcePosition

Diff for: presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala

+12-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
package dotty.tools.pc
1+
package dotty.tools
2+
package pc
23

34
import scala.annotation.tailrec
45

5-
import dotty.tools.dotc.ast.tpd
6-
import dotty.tools.dotc.ast.tpd.*
7-
import dotty.tools.dotc.ast.untpd
8-
import dotty.tools.dotc.core.Contexts.*
9-
import dotty.tools.dotc.core.Flags.*
10-
import dotty.tools.dotc.core.Names.Name
11-
import dotty.tools.dotc.core.StdNames
12-
import dotty.tools.dotc.core.Symbols.*
13-
import dotty.tools.dotc.core.Types.Type
14-
import dotty.tools.dotc.interactive.SourceTree
15-
import dotty.tools.dotc.util.SourceFile
16-
import dotty.tools.dotc.util.SourcePosition
6+
import dotc.*
7+
import ast.*, tpd.*
8+
import core.*, Contexts.*, Decorators.*, Flags.*, Names.*, Symbols.*, Types.*
9+
import interactive.*
10+
import util.*
11+
import util.SourcePosition
1712

1813
object MetalsInteractive:
1914

@@ -205,7 +200,10 @@ object MetalsInteractive:
205200
Nil
206201

207202
case path @ head :: tail =>
208-
if head.symbol.is(Synthetic) then
203+
if head.symbol.is(Exported) then
204+
val sym = head.symbol.sourceSymbol
205+
List((sym, sym.info))
206+
else if head.symbol.is(Synthetic) then
209207
enclosingSymbolsWithExpressionType(
210208
tail,
211209
pos,

Diff for: presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class PcDefinitionProvider(
124124
val isLocal = sym.source == pos.source
125125
if isLocal then
126126
val defs =
127-
Interactive.findDefinitions(List(sym), driver, false, false)
127+
Interactive.findDefinitions(List(sym), driver, false, false).filter(_.source == sym.source)
128128
defs.headOption match
129129
case Some(srcTree) =>
130130
val pos = srcTree.namePos

Diff for: presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala

+75
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,81 @@ class PcDefinitionSuite extends BasePcDefinitionSuite:
199199
|""".stripMargin
200200
)
201201

202+
@Test def exportType0 =
203+
check(
204+
"""object Foo:
205+
| trait <<Cat>>
206+
|object Bar:
207+
| export Foo.*
208+
|class Test:
209+
| import Bar.*
210+
| def test = new Ca@@t {}
211+
|""".stripMargin
212+
)
213+
214+
@Test def exportType1 =
215+
check(
216+
"""object Foo:
217+
| trait <<Cat>>[A]
218+
|object Bar:
219+
| export Foo.*
220+
|class Test:
221+
| import Bar.*
222+
| def test = new Ca@@t[Int] {}
223+
|""".stripMargin
224+
)
225+
226+
@Test def exportTerm0Nullary =
227+
check(
228+
"""trait Foo:
229+
| def <<meth>>: Int
230+
|class Bar(val foo: Foo):
231+
| export foo.*
232+
| def test(bar: Bar) = bar.me@@th
233+
|""".stripMargin
234+
)
235+
236+
@Test def exportTerm0 =
237+
check(
238+
"""trait Foo:
239+
| def <<meth>>(): Int
240+
|class Bar(val foo: Foo):
241+
| export foo.*
242+
| def test(bar: Bar) = bar.me@@th()
243+
|""".stripMargin
244+
)
245+
246+
@Test def exportTerm1 =
247+
check(
248+
"""trait Foo:
249+
| def <<meth>>(x: Int): Int
250+
|class Bar(val foo: Foo):
251+
| export foo.*
252+
| def test(bar: Bar) = bar.me@@th(0)
253+
|""".stripMargin
254+
)
255+
256+
@Test def exportTerm1Poly =
257+
check(
258+
"""trait Foo:
259+
| def <<meth>>[A](x: A): A
260+
|class Bar(val foo: Foo):
261+
| export foo.*
262+
| def test(bar: Bar) = bar.me@@th(0)
263+
|""".stripMargin
264+
)
265+
266+
@Test def exportTerm1Overload =
267+
check(
268+
"""trait Foo:
269+
| def <<meth>>(x: Int): Int
270+
| def meth(x: String): String
271+
|class Bar(val foo: Foo):
272+
| export foo.*
273+
| def test(bar: Bar) = bar.me@@th(0)
274+
|""".stripMargin
275+
)
276+
202277
@Test def `named-arg-local` =
203278
check(
204279
"""|

0 commit comments

Comments
 (0)