diff --git a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala index ffd7377c8181..f7fdb1c36e6d 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala @@ -62,7 +62,7 @@ object CompletionItemResolver extends ItemResolver: if companion == NoSymbol || gsym.is(JavaDefined) then if gsymDoc.isEmpty() then if gsym.isAliasType then - fullDocstring(gsym.info.deepDealias.typeSymbol, search) + fullDocstring(gsym.info.deepDealiasAndSimplify.typeSymbol, search) else if gsym.is(Method) then gsym.info.finalResultType match case tr @ TermRef(_, sym) => diff --git a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala index 746be65155d9..d86b3d2eb2c4 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala @@ -110,22 +110,23 @@ object HoverProvider: if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic => fallbackToDynamics(path, printer, contentType) case symbolTpes @ ((symbol, tpe, None) :: _) => - val exprTpw = tpe.widenTermRefExpr.deepDealias + val exprTpw = tpe.widenTermRefExpr.deepDealiasAndSimplify val hoverString = tpw match // https://github.com/scala/scala3/issues/8891 case tpw: ImportType => printer.hoverSymbol(symbol, symbol.paramRef) case _ => - val (tpe, sym) = + val (innerTpe, sym) = if symbol.isType then (symbol.typeRef, symbol) else enclosing.head.seenFrom(symbol) val finalTpe = - if tpe != NoType then tpe + if tpe.isNamedTupleType then tpe.widenTermRefExpr + else if innerTpe != NoType then innerTpe else tpw - printer.hoverSymbol(sym, finalTpe.deepDealias) + printer.hoverSymbol(sym, finalTpe.deepDealiasAndSimplify) end match end hoverString @@ -161,7 +162,7 @@ object HoverProvider: ju.Optional.empty().nn end match case (_, tpe, Some(namedTupleArg)) :: _ => - val exprTpw = tpe.widenTermRefExpr.deepDealias + val exprTpw = tpe.widenTermRefExpr.deepDealiasAndSimplify printer.expressionType(exprTpw) match case Some(tpe) => ju.Optional.of( @@ -194,7 +195,7 @@ object HoverProvider: val resultType = rest match case Select(_, asInstanceOf) :: TypeApply(_, List(tpe)) :: _ if asInstanceOf == nme.asInstanceOfPM => - tpe.tpe.widenTermRefExpr.deepDealias + tpe.tpe.widenTermRefExpr.deepDealiasAndSimplify case _ if n == nme.selectDynamic => tpe.resultType case _ => tpe @@ -220,9 +221,9 @@ object HoverProvider: findRefinement(parent) case _ => None - val refTpe = sel.typeOpt.widen.deepDealias match + val refTpe = sel.typeOpt.widen.deepDealiasAndSimplify match case r: RefinedType => Some(r) - case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealias) + case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealiasAndSimplify) case _ => None refTpe.flatMap(findRefinement).asJava diff --git a/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala index 2006774ae19b..3d4cc45171ae 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala @@ -99,9 +99,8 @@ final class InferredTypeProvider( case AppliedType(tycon, args) => isInScope(tycon) && args.forall(isInScope) case _ => true - if isInScope(tpe) - then tpe - else tpe.deepDealias + if isInScope(tpe) then tpe + else tpe.deepDealiasAndSimplify val printer = ShortenedTypePrinter( symbolSearch, diff --git a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala index 8132b0cf95cb..eec8ecde8945 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala @@ -206,7 +206,7 @@ object MetalsInteractive: // Handle select on named tuples case (Apply(Apply(TypeApply(fun, List(t1, t2)), List(ddef)), List(Literal(Constant(i: Int))))) :: _ if fun.symbol.exists && fun.symbol.name == nme.apply && - fun.symbol.owner.exists && fun.symbol.owner == getModuleIfDefined("scala.NamedTuple").moduleClass => + fun.symbol.owner.exists && fun.symbol.owner == defn.NamedTupleModule.moduleClass => def getIndex(t: Tree): Option[Type] = t.tpe.dealias match case AppliedType(_, args) => args.get(i) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index 8718eaf58a88..0734468754c0 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -140,7 +140,7 @@ class PcInlayHintsProvider( isInScope(tycon) && args.forall(isInScope) case _ => true if isInScope(tpe) then tpe - else tpe.deepDealias(using indexedCtx.ctx) + else tpe.deepDealiasAndSimplify(using indexedCtx.ctx) val dealiased = optDealias(tpe) val tpeStr = printer.tpe(dealiased) diff --git a/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala index 8bed605a87f8..09805fc76040 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Names.* import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Symbols.* -import dotty.tools.pc.utils.InteractiveEnrichments.deepDealias +import dotty.tools.pc.utils.InteractiveEnrichments.deepDealiasAndSimplify import dotty.tools.pc.SemanticdbSymbols import dotty.tools.pc.utils.InteractiveEnrichments.allSymbols import dotty.tools.pc.utils.InteractiveEnrichments.stripBackticks @@ -51,7 +51,7 @@ class SymbolInformationProvider(using Context): collect(classSym) visited.toList.map(SemanticdbSymbols.symbolName) val dealisedSymbol = - if sym.isAliasType then sym.info.deepDealias.typeSymbol else sym + if sym.isAliasType then sym.info.deepDealiasAndSimplify.typeSymbol else sym val classOwner = sym.ownersIterator.drop(1).find(s => s.isClass || s.is(Flags.Module)) val overridden = sym.denot.allOverriddenSymbols.toList diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala index 4fbf22e2294c..185f3f87f42e 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala @@ -93,7 +93,7 @@ object CaseKeywordCompletion: case (Ident(v), tpe) => v.decoded == value case (Select(_, v), tpe) => v.decoded == value case t => false - .map((_, id) => argPts(id).widen.deepDealias) + .map((_, id) => argPts(id).widen.deepDealiasAndSimplify) /* Parent is a function expecting a case match expression */ case TreeApply(fun, _) if !fun.tpe.isErroneous => fun.tpe.paramInfoss match @@ -103,12 +103,12 @@ object CaseKeywordCompletion: ) => val args = head.argTypes.init if args.length > 1 then - Some(definitions.tupleType(args).widen.deepDealias) - else args.headOption.map(_.widen.deepDealias) + Some(definitions.tupleType(args).widen.deepDealiasAndSimplify) + else args.headOption.map(_.widen.deepDealiasAndSimplify) case _ => None case _ => None case sel => - Some(sel.tpe.widen.deepDealias) + Some(sel.tpe.widen.deepDealiasAndSimplify) selTpe .collect { case selTpe if selTpe != NoType => @@ -279,8 +279,8 @@ object CaseKeywordCompletion: clientSupportsSnippets ) - val tpeStr = printer.tpe(selector.tpe.widen.deepDealias.bounds.hi) - val tpe = selector.typeOpt.widen.deepDealias.bounds.hi match + val tpeStr = printer.tpe(selector.tpe.widen.deepDealiasAndSimplify.bounds.hi) + val tpe = selector.typeOpt.widen.deepDealiasAndSimplify.bounds.hi match case tr @ TypeRef(_, _) => tr.underlying case t => t diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala index 53c4e01980bc..621ef2e5c158 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala @@ -42,7 +42,7 @@ object SingletonCompletions: } yield value private def collectSingletons(tpe: Type)(using Context): List[Constant] = - tpe.deepDealias match + tpe.deepDealiasAndSimplify match case ConstantType(value) => List(value) case OrType(tpe1, tpe2) => collectSingletons(tpe1) ++ collectSingletons(tpe2) diff --git a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala index d42795ffd60d..a9cfc9dfb690 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala @@ -215,7 +215,9 @@ class ShortenedTypePrinter( case ConstantType(const) => toText(const) case _ => toTextRef(tp) ~ ".type" - def tpe(tpe: Type): String = toText(tpe).mkString(defaultWidth, false) + def tpe(tpe: Type): String = + val dealiased = if (tpe.isNamedTupleType) tpe.deepDealiasAndSimplify else tpe + toText(dealiased).mkString(defaultWidth, false) def hoverSymbol(sym: Symbol, info: Type)(using Context): String = val typeSymbol = info.typeSymbol diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala index f5c18160b5fd..7309d89577c7 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala @@ -178,7 +178,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: if sym.is(Module) then sym.companionClass else sym.companionModule def dealiasType: Symbol = - if sym.isType then sym.info.deepDealias.typeSymbol else sym + if sym.isType then sym.info.deepDealiasAndSimplify.typeSymbol else sym def nameBackticked: String = nameBackticked(Set.empty[String]) @@ -402,17 +402,18 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: end extension extension (tpe: Type) - def deepDealias(using Context): Type = - tpe.dealias match + def deepDealiasAndSimplify(using Context): Type = + val dealiased = tpe.dealias match case app @ AppliedType(tycon, params) => - AppliedType(tycon, params.map(_.deepDealias)) + AppliedType(tycon, params.map(_.deepDealiasAndSimplify)) case aliasingBounds: AliasingBounds => aliasingBounds.derivedAlias(aliasingBounds.alias.dealias) case TypeBounds(lo, hi) => TypeBounds(lo.dealias, hi.dealias) case RefinedType(parent, name, refinedInfo) => - RefinedType(parent.dealias, name, refinedInfo.deepDealias) + RefinedType(parent.dealias, name, refinedInfo.deepDealiasAndSimplify) case dealised => dealised + if tpe.isNamedTupleType then dealiased.simplified else dealiased extension[T] (list: List[T]) def get(n: Int): Option[T] = if 0 <= n && n < list.size then Some(list(n)) else None diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index e9f58ee45df8..0bad5f41348d 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -2041,6 +2041,21 @@ class CompletionSuite extends BaseCompletionSuite: filter = _.contains("name") ) + @Test def `namedTuple-completions-2` = + check( + """|import scala.NamedTuple.* + | + |def hello = (path = ".", num = 5)++ (line = 1) + |val hello2 = (path = ".", num = 5)++ (line = 1) + | + |@main def bla = + | hello@@ + |""".stripMargin, + """|hello2: (path : String, num : Int, line : Int) + |hello: (path : String, num : Int, line : Int) + """.stripMargin, + ) + @Test def `Selectable with namedTuple Fields member` = check( """|import scala.NamedTuple.* diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala index c1a84d6abb79..212b19d31461 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala @@ -970,6 +970,26 @@ class InsertInferredTypeSuite extends BaseCodeActionSuite: |""".stripMargin ) + @Test def `named-tuples` = + checkEdit( + """|def hello = (path = ".", num = 5) + | + |def <> = + | hello ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = test + |""".stripMargin, + """|def hello = (path = ".", num = 5) + | + |def test: (path : String, num : Int, line : Int) = + | hello ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = test + |""".stripMargin + ) + def checkEdit( original: String, expected: String diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala index 2fcb4e068ee0..3f55352804b4 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala @@ -745,6 +745,47 @@ class HoverTermSuite extends BaseHoverSuite: "name: String".hover ) + + @Test def `named-tuples3`: Unit = + check( + """|def hello = (path = ".", num = 5) + | + |def test = + | hello ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = t@@est + |""".stripMargin, + "def test: (path : String, num : Int, line : Int)".hover + ) + + + @Test def `named-tuples4`: Unit = + check( + """|def hello = (path = ".", num = 5) + | + |def test = + | hel@@lo ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = test + |""".stripMargin, + "def hello: (path : String, num : Int)".hover + ) + + @Test def `named-tuples5`: Unit = + check( + """|def hello = (path = ".", num = 5) + | + |def test(x: (path: String, num: Int)) = + | x ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = t@@est(hello) + |""".stripMargin, + "def test(x: (path : String, num : Int)): (path : String, num : Int, line : Int)".hover + ) + @Test def `value-of`: Unit = check( """|enum Foo(val key: String) { diff --git a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala index bf917f05669b..44a67634aa4d 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala @@ -1055,4 +1055,24 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin ) + + @Test def `named-tuples` = + check( + """|def hello = (path = ".", num = 5) + | + |def test = + | hello ++ (line = 1) + | + |@main def bla = + | val x: (path: String, num: Int, line: Int) = test + |""".stripMargin, + """|def hello/*: (path : String<>, num : Int<>)*/ = (path = ".", num = 5)/*[(String<>, Int<>)]*/ + | + |def test/*: (path : String<>, num : Int<>, line : Int<>)*/ = + | hello ++/*[Tuple1<>["line"], Tuple1<>[Int<>]]*/ (line = 1)/*(using refl<>)*//*[Tuple1<>[Int<>]]*/ + | + |@main def bla/*: Unit<>*/ = + | val x: (path: String, num: Int, line: Int) = test + |""".stripMargin + ) }