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..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) @@ -405,6 +407,36 @@ 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, + ) + 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| 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..2efcba48e82d 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,24 @@ 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 (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 => fun.tpe.paramInfoss match case (head :: Nil) :: _ @@ -105,7 +121,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( 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..03c4fa2bc5bc 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,49 @@ 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 scala + |""".stripMargin + ) + check( + s"""|object Main { + | (null: Option[Option[Option[Option[Int]]]]) match + | case Some(Some(Some(Som@@)))) + |} + |""".stripMargin, + """|Some(value) scala + |Some scala + |""".stripMargin + ) + check( + s"""|object Main { + | Option(Option(1)) match { + | case Some(Som@@) + |} + |""".stripMargin, + """|Some(value) scala + |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 test.Test + |""".stripMargin + ) + @Test def pat1 = check( s"""|object Main { @@ -641,7 +684,8 @@ class CompletionSuite extends BaseCompletionSuite: | case List(Som@@) |} |""".stripMargin, - """|Some[A](value: A): Some[A] + """|Some(value) scala + |Some scala |Some scala |""".stripMargin )