From f6bf36d22c0f00314dc38c1db9a7c2a446d2744c Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Sat, 27 Apr 2024 00:44:16 -0400 Subject: [PATCH 1/5] Add unapply pattern completion test --- .../pc/tests/completion/CompletionSuite.scala | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) 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 b5db258601bc..51f4032c56a3 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -634,6 +634,30 @@ class CompletionSuite extends BaseCompletionSuite: |""".stripMargin ) + @Test def patRecursive = + check( + s"""|object Main { + | Option(List(Option(1))) match { + | case Some(List(None, Som@@)) + |} + |""".stripMargin, + """|Some(value) scala + |Some[A](value: A): Some[A] + |Some scala + |""".stripMargin + ) + check( + s"""|object Main { + | Option(Option(1)) match { + | case Some(Som@@) + |} + |""".stripMargin, + """|Some(value) scala + |Some[A](value: A): Some[A] + |Some scala + |""".stripMargin + ) + @Test def pat1 = check( s"""|object Main { @@ -641,7 +665,9 @@ class CompletionSuite extends BaseCompletionSuite: | case List(Som@@) |} |""".stripMargin, - """|Some[A](value: A): Some[A] + """|Some(value) scala + |Some scala + |Some[A](value: A): Some[A] |Some scala |""".stripMargin ) From 433a89731aa518287a5d6c7742e6efbaee335de2 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Fri, 5 Apr 2024 23:28:18 +0200 Subject: [PATCH 2/5] Add pattern completion based on the Unapply argument type The idea was to collect patterns given the Unapply tree as the parent. We need to deconstruct the UnApply type tree and get the type of the placeholder ident. --- .../tools/pc/completions/Completions.scala | 16 ++++++++++++++++ .../pc/completions/MatchCaseCompletions.scala | 18 +++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala index fb39102399ba..f6b7d6bdf436 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala @@ -405,6 +405,22 @@ class Completions( true, ) + // unapply pattern + case Ident(name) :: (unapp : UnApply) :: _ => + ( + CaseKeywordCompletion.contribute( + EmptyTree, // no selector + completionPos, + indexedContext, + config, + search, + parent = unapp, + autoImports, + patternOnly = Some(name.decoded) + ), + false, + ) + // class FooImpl extends Foo: // def x| case OverrideExtractor(td, completing, start, exhaustive, fallbackName) => 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 48c6bcfe8317..92e5d81fbe02 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala @@ -27,6 +27,8 @@ import dotty.tools.dotc.core.Types.NoType import dotty.tools.dotc.core.Types.OrType import dotty.tools.dotc.core.Types.Type import dotty.tools.dotc.core.Types.TypeRef +import dotty.tools.dotc.core.Types.AppliedType +import dotty.tools.dotc.typer.Applications.UnapplyArgs import dotty.tools.dotc.util.SourcePosition import dotty.tools.pc.AutoImports.AutoImportsGenerator import dotty.tools.pc.AutoImports.SymbolImport @@ -75,10 +77,23 @@ object CaseKeywordCompletion: patternOnly, hasBind ) + val printer = ShortenedTypePrinter(search, IncludeDefaultParam.Never)(using indexedContext) val selTpe = selector match case EmptyTree => parent match + /* Parent is an unapply pattern */ + case UnApply(fn, implicits, patterns) if !fn.tpe.isErroneous => + patternOnly match + case None => None + case Some(value) => + val argPts = UnapplyArgs(fn.tpe.widen.finalResultType, fn, patterns, parent.srcPos).argTypes + patterns.zipWithIndex + .find: + case (id@Ident(v), tpe) => v.decoded == value + case _ => false + .map((_, id) => argPts(id).widen.deepDealias) + /* Parent is a function expecting a case match expression */ case TreeApply(fun, _) if !fun.tpe.isErroneous => fun.tpe.paramInfoss match case (head :: Nil) :: _ @@ -105,7 +120,8 @@ object CaseKeywordCompletion: if patternOnly.isEmpty then val selectorTpe = selTpe.show val tpeLabel = - if !selectorTpe.contains("x$1") then selectorTpe + if !selectorTpe.contains("x$1") /* selector of a function type? */ then + selectorTpe else selector.symbol.info.show val label = s"case ${tpeLabel} =>" List( From 67e6505c359baac863b36cec7c086022b656462b Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Tue, 7 May 2024 15:15:09 +0200 Subject: [PATCH 3/5] Add more tests for deeply nested patterns and patterns with Select instead of Ident --- .../pc/tests/completion/CompletionSuite.scala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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 51f4032c56a3..ba31ac83efd4 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -646,6 +646,17 @@ class CompletionSuite extends BaseCompletionSuite: |Some scala |""".stripMargin ) + check( + s"""|object Main { + | (null: Option[Option[Option[Option[Int]]]]) match + | case Some(Some(Some(Som@@)))) + |} + |""".stripMargin, + """|Some(value) scala + |Some[A](value: A): Some[A] + |Some scala + |""".stripMargin + ) check( s"""|object Main { | Option(Option(1)) match { @@ -657,6 +668,18 @@ class CompletionSuite extends BaseCompletionSuite: |Some scala |""".stripMargin ) + check( + s"""|object Test: + | case class NestedClass(x: Int) + |object TestRun: + | Option(Test.NestedClass(5)) match + | case Some(Test.Neste@@) + |""".stripMargin, + """|NestedClass(x) test.Test + |NestedClass(x: Int): NestedClass + |NestedClass test.Test + |""".stripMargin + ) @Test def pat1 = check( From a399946afe0977e275e77d44283790eaf982072a Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Tue, 7 May 2024 15:15:25 +0200 Subject: [PATCH 4/5] Contribute candidates when the selection is a Select --- .../dotty/tools/pc/completions/Completions.scala | 14 ++++++++++++++ .../pc/completions/MatchCaseCompletions.scala | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala index f6b7d6bdf436..7aa94d6c6913 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala @@ -420,6 +420,20 @@ class Completions( ), false, ) + case Select(_, name) :: (unapp : UnApply) :: _ => + ( + CaseKeywordCompletion.contribute( + EmptyTree, // no selector + completionPos, + indexedContext, + config, + search, + parent = unapp, + autoImports, + patternOnly = Some(name.decoded) + ), + false, + ) // class FooImpl extends Foo: // def x| 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 92e5d81fbe02..2efcba48e82d 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala @@ -90,8 +90,9 @@ object CaseKeywordCompletion: val argPts = UnapplyArgs(fn.tpe.widen.finalResultType, fn, patterns, parent.srcPos).argTypes patterns.zipWithIndex .find: - case (id@Ident(v), tpe) => v.decoded == value - case _ => false + case (Ident(v), tpe) => v.decoded == value + case (Select(_, v), tpe) => v.decoded == value + case t => false .map((_, id) => argPts(id).widen.deepDealias) /* Parent is a function expecting a case match expression */ case TreeApply(fun, _) if !fun.tpe.isErroneous => From fbfcdf867c3efbcba745734e3ec01f3c26cb10c4 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Tue, 7 May 2024 15:20:44 +0200 Subject: [PATCH 5/5] Remove redundant cases with UnApply --- .../src/main/dotty/tools/pc/completions/Completions.scala | 2 ++ .../dotty/tools/pc/tests/completion/CompletionSuite.scala | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala index 7aa94d6c6913..db578e32663f 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala @@ -70,6 +70,8 @@ class Completions( false case (_: (Import | Export)) :: _ => false case _ :: (_: (Import | Export)) :: _ => false + // UnApply has patterns included in MatchCaseCompletions + case _ :: (_: UnApply) :: _ => false case _ => true private lazy val isNew: Boolean = Completion.isInNewContext(adjustedPath) 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 ba31ac83efd4..03c4fa2bc5bc 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -642,7 +642,6 @@ class CompletionSuite extends BaseCompletionSuite: |} |""".stripMargin, """|Some(value) scala - |Some[A](value: A): Some[A] |Some scala |""".stripMargin ) @@ -653,7 +652,6 @@ class CompletionSuite extends BaseCompletionSuite: |} |""".stripMargin, """|Some(value) scala - |Some[A](value: A): Some[A] |Some scala |""".stripMargin ) @@ -664,7 +662,6 @@ class CompletionSuite extends BaseCompletionSuite: |} |""".stripMargin, """|Some(value) scala - |Some[A](value: A): Some[A] |Some scala |""".stripMargin ) @@ -676,7 +673,6 @@ class CompletionSuite extends BaseCompletionSuite: | case Some(Test.Neste@@) |""".stripMargin, """|NestedClass(x) test.Test - |NestedClass(x: Int): NestedClass |NestedClass test.Test |""".stripMargin ) @@ -690,7 +686,6 @@ class CompletionSuite extends BaseCompletionSuite: |""".stripMargin, """|Some(value) scala |Some scala - |Some[A](value: A): Some[A] |Some scala |""".stripMargin )