Skip to content

fix: simplify infer type for apply #23434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ class InferExpectedType(
val indexedCtx = IndexedContext(pos)(using locatedCtx)
val printer =
ShortenedTypePrinter(search, IncludeDefaultParam.ResolveLater)(using indexedCtx)
InterCompletionType.inferType(path)(using newctx).map{
InferCompletionType.inferType(path)(using newctx).map{
tpe => printer.tpe(tpe)
}
case None => None

object InterCompletionType:
object InferCompletionType:
def inferType(path: List[Tree])(using Context): Option[Type] =
path match
case (lit: Literal) :: Select(Literal(_), _) :: Apply(Select(Literal(_), _), List(s: Select)) :: rest if s.symbol == defn.Predef_undefined => inferType(rest, lit.span)
Expand Down Expand Up @@ -94,37 +94,7 @@ object InterCompletionType:
else Some(UnapplyArgs(fun.tpe.finalResultType, fun, pats, NoSourcePosition).argTypes(ind))
// f(@@)
case ApplyExtractor(app) =>
val argsAndParams = ApplyArgsExtractor.getArgsAndParams(None, app, span).headOption
argsAndParams.flatMap:
case (args, params) =>
val idx = args.indexWhere(_.span.contains(span))
val param =
if idx >= 0 && params.length > idx then Some(params(idx).info)
else None
param match
// def f[T](a: T): T = ???
// f[Int](@@)
// val _: Int = f(@@)
case Some(t : TypeRef) if t.symbol.is(Flags.TypeParam) =>
for
(typeParams, args) <-
app match
case Apply(TypeApply(fun, args), _) =>
val typeParams = fun.symbol.paramSymss.headOption.filter(_.forall(_.isTypeParam))
typeParams.map((_, args.map(_.tpe)))
// val f: (j: "a") => Int
// f(@@)
case Apply(Select(v, StdNames.nme.apply), _) =>
v.symbol.info match
case AppliedType(des, args) =>
Some((des.typeSymbol.typeParams, args))
case _ => None
case _ => None
ind = typeParams.indexOf(t.symbol)
tpe <- args.get(ind)
if !tpe.isErroneous
yield tpe
case Some(tpe) => Some(tpe)
case _ => None
val idx = app.args.indexWhere(_.span.contains(span))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Och wow, that is much simpler!

app.fun.tpe.widenTermRefExpr.paramInfoss.flatten.get(idx)
case _ => None

Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ class Completions(
config.isCompletionSnippetsEnabled()
)
(args, false)
val singletonCompletions = InterCompletionType.inferType(path).map(
val singletonCompletions = InferCompletionType.inferType(path).map(
SingletonCompletions.contribute(path, _, completionPos)
).getOrElse(Nil)
(singletonCompletions ++ advanced, exclusive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ class InferExpectedTypeSuite extends BasePCSuite:
|""".stripMargin
)

@Test def `basic-params` =
check(
"""|def paint(c: Int, f: String, d: List[String]) = ???
|val _ = paint(1, "aa", @@)
|""".stripMargin,
"""|List[String]
|""".stripMargin
)

@Test def `basic-type-param` =
check(
"""|def paint[T](c: T) = ???
|val _ = paint[Int](@@)
|""".stripMargin,
"""|Int
|""".stripMargin
)

@Test def `type-ascription` =
check(
"""|def doo = (@@ : Double)
Expand Down Expand Up @@ -335,3 +353,60 @@ class InferExpectedTypeSuite extends BasePCSuite:
"""|String
|""".stripMargin
)

@Test def using =
check(
"""|def go(using Ordering[Int])(x: Int, y: Int): Int =
| Ordering[Int].compare(x, y)
|
|def test =
| go(???, @@)
|""".stripMargin,
"""|Int
|""".stripMargin
)

@Test def `apply-dynamic` =
check(
"""|object TypedHoleApplyDynamic {
| val obj: reflect.Selectable {
| def method(x: Int): Unit
| } = new reflect.Selectable {
| def method(x: Int): Unit = ()
| }
|
| obj.method(@@)
|}
|""".stripMargin,
"Int"
)

@Test def `apply-dynamic-2` =
check(
"""|object TypedHoleApplyDynamic {
| val obj: reflect.Selectable {
| def method[T](x: Int, y: T): Unit
| } = new reflect.Selectable {
| def method[T](x: Int, y: T): Unit = ()
| }
|
| obj.method[String](1, @@)
|}
|""".stripMargin,
"String"
)

@Test def `apply-dynamic-3` =
check(
"""|object TypedHoleApplyDynamic {
| val obj: reflect.Selectable {
| def method[T](a: Int)(x: Int, y: T): Unit
| } = new reflect.Selectable {
| def method[T](a: Int)(x: Int, y: T): Unit = ()
| }
|
| obj.method[String](1)(1, @@)
|}
|""".stripMargin,
"String"
)
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,30 @@ class SingletonCompletionsSuite extends BaseCompletionSuite {
"""|"foo": "foo"
|""".stripMargin
)

@Test def `type-apply` =
check(
"""|class Consumer[A]:
| def eat(a: A) = ()
|
|def test =
| Consumer[7].eat(@@)
|""".stripMargin,
"7: 7",
topLines = Some(1)
)

@Test def `type-apply-2` =
check(
"""|class Consumer[A]:
| def eat(a: A) = ()
|
|object Consumer7 extends Consumer[7]
|
|def test =
| Consumer7.eat(@@)
|""".stripMargin,
"7: 7",
topLines = Some(1)
)
}
Loading