Skip to content

Commit eb6d3a8

Browse files
authored
improvement: Don't dealias named tuples for type hints (#23013)
This causes the code to grow quite a lot. Fixes scalameta/metals#7397
1 parent 0ae343f commit eb6d3a8

14 files changed

+128
-29
lines changed

presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ object CompletionItemResolver extends ItemResolver:
6262
if companion == NoSymbol || gsym.is(JavaDefined) then
6363
if gsymDoc.isEmpty() then
6464
if gsym.isAliasType then
65-
fullDocstring(gsym.info.deepDealias.typeSymbol, search)
65+
fullDocstring(gsym.info.deepDealiasAndSimplify.typeSymbol, search)
6666
else if gsym.is(Method) then
6767
gsym.info.finalResultType match
6868
case tr @ TermRef(_, sym) =>

presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala

+9-8
Original file line numberDiff line numberDiff line change
@@ -110,22 +110,23 @@ object HoverProvider:
110110
if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic =>
111111
fallbackToDynamics(path, printer, contentType)
112112
case symbolTpes @ ((symbol, tpe, None) :: _) =>
113-
val exprTpw = tpe.widenTermRefExpr.deepDealias
113+
val exprTpw = tpe.widenTermRefExpr.deepDealiasAndSimplify
114114
val hoverString =
115115
tpw match
116116
// https://github.com/scala/scala3/issues/8891
117117
case tpw: ImportType =>
118118
printer.hoverSymbol(symbol, symbol.paramRef)
119119
case _ =>
120-
val (tpe, sym) =
120+
val (innerTpe, sym) =
121121
if symbol.isType then (symbol.typeRef, symbol)
122122
else enclosing.head.seenFrom(symbol)
123123

124124
val finalTpe =
125-
if tpe != NoType then tpe
125+
if tpe.isNamedTupleType then tpe.widenTermRefExpr
126+
else if innerTpe != NoType then innerTpe
126127
else tpw
127128

128-
printer.hoverSymbol(sym, finalTpe.deepDealias)
129+
printer.hoverSymbol(sym, finalTpe.deepDealiasAndSimplify)
129130
end match
130131
end hoverString
131132

@@ -161,7 +162,7 @@ object HoverProvider:
161162
ju.Optional.empty().nn
162163
end match
163164
case (_, tpe, Some(namedTupleArg)) :: _ =>
164-
val exprTpw = tpe.widenTermRefExpr.deepDealias
165+
val exprTpw = tpe.widenTermRefExpr.deepDealiasAndSimplify
165166
printer.expressionType(exprTpw) match
166167
case Some(tpe) =>
167168
ju.Optional.of(
@@ -194,7 +195,7 @@ object HoverProvider:
194195
val resultType =
195196
rest match
196197
case Select(_, asInstanceOf) :: TypeApply(_, List(tpe)) :: _ if asInstanceOf == nme.asInstanceOfPM =>
197-
tpe.tpe.widenTermRefExpr.deepDealias
198+
tpe.tpe.widenTermRefExpr.deepDealiasAndSimplify
198199
case _ if n == nme.selectDynamic => tpe.resultType
199200
case _ => tpe
200201

@@ -220,9 +221,9 @@ object HoverProvider:
220221
findRefinement(parent)
221222
case _ => None
222223

223-
val refTpe = sel.typeOpt.widen.deepDealias match
224+
val refTpe = sel.typeOpt.widen.deepDealiasAndSimplify match
224225
case r: RefinedType => Some(r)
225-
case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealias)
226+
case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealiasAndSimplify)
226227
case _ => None
227228

228229
refTpe.flatMap(findRefinement).asJava

presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,8 @@ final class InferredTypeProvider(
9999
case AppliedType(tycon, args) =>
100100
isInScope(tycon) && args.forall(isInScope)
101101
case _ => true
102-
if isInScope(tpe)
103-
then tpe
104-
else tpe.deepDealias
102+
if isInScope(tpe) then tpe
103+
else tpe.deepDealiasAndSimplify
105104

106105
val printer = ShortenedTypePrinter(
107106
symbolSearch,

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ object MetalsInteractive:
206206
// Handle select on named tuples
207207
case (Apply(Apply(TypeApply(fun, List(t1, t2)), List(ddef)), List(Literal(Constant(i: Int))))) :: _
208208
if fun.symbol.exists && fun.symbol.name == nme.apply &&
209-
fun.symbol.owner.exists && fun.symbol.owner == getModuleIfDefined("scala.NamedTuple").moduleClass =>
209+
fun.symbol.owner.exists && fun.symbol.owner == defn.NamedTupleModule.moduleClass =>
210210
def getIndex(t: Tree): Option[Type] =
211211
t.tpe.dealias match
212212
case AppliedType(_, args) => args.get(i)

presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class PcInlayHintsProvider(
140140
isInScope(tycon) && args.forall(isInScope)
141141
case _ => true
142142
if isInScope(tpe) then tpe
143-
else tpe.deepDealias(using indexedCtx.ctx)
143+
else tpe.deepDealiasAndSimplify(using indexedCtx.ctx)
144144

145145
val dealiased = optDealias(tpe)
146146
val tpeStr = printer.tpe(dealiased)

presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Flags
1111
import dotty.tools.dotc.core.Names.*
1212
import dotty.tools.dotc.core.StdNames.nme
1313
import dotty.tools.dotc.core.Symbols.*
14-
import dotty.tools.pc.utils.InteractiveEnrichments.deepDealias
14+
import dotty.tools.pc.utils.InteractiveEnrichments.deepDealiasAndSimplify
1515
import dotty.tools.pc.SemanticdbSymbols
1616
import dotty.tools.pc.utils.InteractiveEnrichments.allSymbols
1717
import dotty.tools.pc.utils.InteractiveEnrichments.stripBackticks
@@ -51,7 +51,7 @@ class SymbolInformationProvider(using Context):
5151
collect(classSym)
5252
visited.toList.map(SemanticdbSymbols.symbolName)
5353
val dealisedSymbol =
54-
if sym.isAliasType then sym.info.deepDealias.typeSymbol else sym
54+
if sym.isAliasType then sym.info.deepDealiasAndSimplify.typeSymbol else sym
5555
val classOwner =
5656
sym.ownersIterator.drop(1).find(s => s.isClass || s.is(Flags.Module))
5757
val overridden = sym.denot.allOverriddenSymbols.toList

presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ object CaseKeywordCompletion:
9393
case (Ident(v), tpe) => v.decoded == value
9494
case (Select(_, v), tpe) => v.decoded == value
9595
case t => false
96-
.map((_, id) => argPts(id).widen.deepDealias)
96+
.map((_, id) => argPts(id).widen.deepDealiasAndSimplify)
9797
/* Parent is a function expecting a case match expression */
9898
case TreeApply(fun, _) if !fun.tpe.isErroneous =>
9999
fun.tpe.paramInfoss match
@@ -103,12 +103,12 @@ object CaseKeywordCompletion:
103103
) =>
104104
val args = head.argTypes.init
105105
if args.length > 1 then
106-
Some(definitions.tupleType(args).widen.deepDealias)
107-
else args.headOption.map(_.widen.deepDealias)
106+
Some(definitions.tupleType(args).widen.deepDealiasAndSimplify)
107+
else args.headOption.map(_.widen.deepDealiasAndSimplify)
108108
case _ => None
109109
case _ => None
110110
case sel =>
111-
Some(sel.tpe.widen.deepDealias)
111+
Some(sel.tpe.widen.deepDealiasAndSimplify)
112112

113113
selTpe
114114
.collect { case selTpe if selTpe != NoType =>
@@ -279,8 +279,8 @@ object CaseKeywordCompletion:
279279
clientSupportsSnippets
280280
)
281281

282-
val tpeStr = printer.tpe(selector.tpe.widen.deepDealias.bounds.hi)
283-
val tpe = selector.typeOpt.widen.deepDealias.bounds.hi match
282+
val tpeStr = printer.tpe(selector.tpe.widen.deepDealiasAndSimplify.bounds.hi)
283+
val tpe = selector.typeOpt.widen.deepDealiasAndSimplify.bounds.hi match
284284
case tr @ TypeRef(_, _) => tr.underlying
285285
case t => t
286286

presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ object SingletonCompletions:
4242
} yield value
4343

4444
private def collectSingletons(tpe: Type)(using Context): List[Constant] =
45-
tpe.deepDealias match
45+
tpe.deepDealiasAndSimplify match
4646
case ConstantType(value) => List(value)
4747
case OrType(tpe1, tpe2) =>
4848
collectSingletons(tpe1) ++ collectSingletons(tpe2)

presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ class ShortenedTypePrinter(
215215
case ConstantType(const) => toText(const)
216216
case _ => toTextRef(tp) ~ ".type"
217217

218-
def tpe(tpe: Type): String = toText(tpe).mkString(defaultWidth, false)
218+
def tpe(tpe: Type): String =
219+
val dealiased = if (tpe.isNamedTupleType) tpe.deepDealiasAndSimplify else tpe
220+
toText(dealiased).mkString(defaultWidth, false)
219221

220222
def hoverSymbol(sym: Symbol, info: Type)(using Context): String =
221223
val typeSymbol = info.typeSymbol

presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala

+6-5
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
178178
if sym.is(Module) then sym.companionClass else sym.companionModule
179179

180180
def dealiasType: Symbol =
181-
if sym.isType then sym.info.deepDealias.typeSymbol else sym
181+
if sym.isType then sym.info.deepDealiasAndSimplify.typeSymbol else sym
182182

183183
def nameBackticked: String = nameBackticked(Set.empty[String])
184184

@@ -402,17 +402,18 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
402402
end extension
403403

404404
extension (tpe: Type)
405-
def deepDealias(using Context): Type =
406-
tpe.dealias match
405+
def deepDealiasAndSimplify(using Context): Type =
406+
val dealiased = tpe.dealias match
407407
case app @ AppliedType(tycon, params) =>
408-
AppliedType(tycon, params.map(_.deepDealias))
408+
AppliedType(tycon, params.map(_.deepDealiasAndSimplify))
409409
case aliasingBounds: AliasingBounds =>
410410
aliasingBounds.derivedAlias(aliasingBounds.alias.dealias)
411411
case TypeBounds(lo, hi) =>
412412
TypeBounds(lo.dealias, hi.dealias)
413413
case RefinedType(parent, name, refinedInfo) =>
414-
RefinedType(parent.dealias, name, refinedInfo.deepDealias)
414+
RefinedType(parent.dealias, name, refinedInfo.deepDealiasAndSimplify)
415415
case dealised => dealised
416+
if tpe.isNamedTupleType then dealiased.simplified else dealiased
416417

417418
extension[T] (list: List[T])
418419
def get(n: Int): Option[T] = if 0 <= n && n < list.size then Some(list(n)) else None

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala

+15
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,21 @@ class CompletionSuite extends BaseCompletionSuite:
20412041
filter = _.contains("name")
20422042
)
20432043

2044+
@Test def `namedTuple-completions-2` =
2045+
check(
2046+
"""|import scala.NamedTuple.*
2047+
|
2048+
|def hello = (path = ".", num = 5)++ (line = 1)
2049+
|val hello2 = (path = ".", num = 5)++ (line = 1)
2050+
|
2051+
|@main def bla =
2052+
| hello@@
2053+
|""".stripMargin,
2054+
"""|hello2: (path : String, num : Int, line : Int)
2055+
|hello: (path : String, num : Int, line : Int)
2056+
""".stripMargin,
2057+
)
2058+
20442059
@Test def `Selectable with namedTuple Fields member` =
20452060
check(
20462061
"""|import scala.NamedTuple.*

presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala

+20
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,26 @@ class InsertInferredTypeSuite extends BaseCodeActionSuite:
970970
|""".stripMargin
971971
)
972972

973+
@Test def `named-tuples` =
974+
checkEdit(
975+
"""|def hello = (path = ".", num = 5)
976+
|
977+
|def <<test>> =
978+
| hello ++ (line = 1)
979+
|
980+
|@main def bla =
981+
| val x: (path: String, num: Int, line: Int) = test
982+
|""".stripMargin,
983+
"""|def hello = (path = ".", num = 5)
984+
|
985+
|def test: (path : String, num : Int, line : Int) =
986+
| hello ++ (line = 1)
987+
|
988+
|@main def bla =
989+
| val x: (path: String, num: Int, line: Int) = test
990+
|""".stripMargin
991+
)
992+
973993
def checkEdit(
974994
original: String,
975995
expected: String

presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala

+41
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,47 @@ class HoverTermSuite extends BaseHoverSuite:
745745
"name: String".hover
746746
)
747747

748+
749+
@Test def `named-tuples3`: Unit =
750+
check(
751+
"""|def hello = (path = ".", num = 5)
752+
|
753+
|def test =
754+
| hello ++ (line = 1)
755+
|
756+
|@main def bla =
757+
| val x: (path: String, num: Int, line: Int) = t@@est
758+
|""".stripMargin,
759+
"def test: (path : String, num : Int, line : Int)".hover
760+
)
761+
762+
763+
@Test def `named-tuples4`: Unit =
764+
check(
765+
"""|def hello = (path = ".", num = 5)
766+
|
767+
|def test =
768+
| hel@@lo ++ (line = 1)
769+
|
770+
|@main def bla =
771+
| val x: (path: String, num: Int, line: Int) = test
772+
|""".stripMargin,
773+
"def hello: (path : String, num : Int)".hover
774+
)
775+
776+
@Test def `named-tuples5`: Unit =
777+
check(
778+
"""|def hello = (path = ".", num = 5)
779+
|
780+
|def test(x: (path: String, num: Int)) =
781+
| x ++ (line = 1)
782+
|
783+
|@main def bla =
784+
| val x: (path: String, num: Int, line: Int) = t@@est(hello)
785+
|""".stripMargin,
786+
"def test(x: (path : String, num : Int)): (path : String, num : Int, line : Int)".hover
787+
)
788+
748789
@Test def `value-of`: Unit =
749790
check(
750791
"""|enum Foo(val key: String) {

presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala

+20
Original file line numberDiff line numberDiff line change
@@ -1055,4 +1055,24 @@ class InlayHintsSuite extends BaseInlayHintsSuite {
10551055
|}
10561056
|""".stripMargin
10571057
)
1058+
1059+
@Test def `named-tuples` =
1060+
check(
1061+
"""|def hello = (path = ".", num = 5)
1062+
|
1063+
|def test =
1064+
| hello ++ (line = 1)
1065+
|
1066+
|@main def bla =
1067+
| val x: (path: String, num: Int, line: Int) = test
1068+
|""".stripMargin,
1069+
"""|def hello/*: (path : String<<java/lang/String#>>, num : Int<<scala/Int#>>)*/ = (path = ".", num = 5)/*[(String<<java/lang/String#>>, Int<<scala/Int#>>)]*/
1070+
|
1071+
|def test/*: (path : String<<java/lang/String#>>, num : Int<<scala/Int#>>, line : Int<<scala/Int#>>)*/ =
1072+
| hello ++/*[Tuple1<<scala/Tuple1#>>["line"], Tuple1<<scala/Tuple1#>>[Int<<scala/Int#>>]]*/ (line = 1)/*(using refl<<scala/`<:<`.refl().>>)*//*[Tuple1<<scala/Tuple1#>>[Int<<scala/Int#>>]]*/
1073+
|
1074+
|@main def bla/*: Unit<<scala/Unit#>>*/ =
1075+
| val x: (path: String, num: Int, line: Int) = test
1076+
|""".stripMargin
1077+
)
10581078
}

0 commit comments

Comments
 (0)