Skip to content

Commit

Permalink
feat: higher-kinded types in suggestions (#1712)
Browse files Browse the repository at this point in the history
Support higher-kinded types when building suggestions.
  • Loading branch information
4e6 authored and iamrecursion committed Jun 24, 2021
1 parent c08629c commit 6e056d2
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
.getOrElse(QualifiedName.simpleName(typeName))
val tdef = TypeArg.Value(qualifiedTypeName)
go(body, args :+ tdef)
case IR.Application.Prefix(tfun, targs, _, _, _, _) =>
val appFunction = go(tfun, Vector()).head
val appArgs = targs.flatMap(arg => go(arg.value, Vector()))
args :+ TypeArg.Application(appFunction, appArgs.toVector)
case tname: IR.Name =>
val typeName = tname.name
val qualifiedTypeName = resolveTypeName(bindings, typeName)
Expand Down Expand Up @@ -468,11 +472,20 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
def go(targ: TypeArg, level: Int): String =
targ match {
case TypeArg.Value(name) => name.toString
case TypeArg.Function(Vector(typeArg)) =>
val typeName = go(typeArg, level)
if (level > 0) s"($typeName)" else typeName
case TypeArg.Function(types) =>
val typeList = types.map(go(_, level + 1))
if (level > 0) typeList.mkString("(", " -> ", ")")
else typeList.mkString(" -> ")
case TypeArg.Application(fun, args) =>
val funText = go(fun, level)
val argsList = args.map(go(_, level + 1)).mkString(" ")
val typeName = s"$funText $argsList"
if (level > 0) s"($typeName)" else typeName
}

go(targ, 0)
}

Expand Down Expand Up @@ -570,6 +583,16 @@ object SuggestionBuilder {
*/
case class Function(signature: Vector[TypeArg]) extends TypeArg

/** Function application, like `Either A B`.
*
* @param function the function type
* @param arguments the list of argument types
*/
case class Application(
function: TypeArg,
arguments: Vector[TypeArg]
) extends TypeArg

}

val Any: String = "Builtins.Main.Any"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,135 @@ class SuggestionBuilderTest extends CompilerTest {
)
}

"build method with a qualified type" in {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""
|foo : Foo.Bar
|foo = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleAtomNode,
Tree.Node(
Suggestion.Method(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument("this", "Unnamed.Test", false, false, None)
),
selfType = "Unnamed.Test",
returnType = "Foo.Bar",
documentation = None
),
Vector()
)
)
)
}

"build method with an argument" in {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""
|foo : Text -> Number
|foo a = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleAtomNode,
Tree.Node(
Suggestion.Method(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument("this", "Unnamed.Test", false, false, None),
Suggestion.Argument("a", "Text", false, false, None)
),
selfType = "Unnamed.Test",
returnType = "Number",
documentation = None
),
Vector()
)
)
)
}

"build method with a type containing higher kinds" in {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""
|foo : Either (Vector Number) Text -> Number
|foo a = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleAtomNode,
Tree.Node(
Suggestion.Method(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument("this", "Unnamed.Test", false, false, None),
Suggestion.Argument(
"a",
"Either (Vector Number) Text",
false,
false,
None
)
),
selfType = "Unnamed.Test",
returnType = "Number",
documentation = None
),
Vector()
)
)
)
}

"build method with a type containing qualified higher kinds" in {
pending // issue #1711
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""
|foo : Foo.Bar Baz
|foo = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleAtomNode,
Tree.Node(
Suggestion.Method(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument("this", "Unnamed.Test", false, false, None)
),
selfType = "Unnamed.Test",
returnType = "Foo.Bar Baz",
documentation = None
),
Vector()
)
)
)
}

"build method with complex body" in {
implicit val moduleContext: ModuleContext = freshModuleContext

Expand Down

0 comments on commit 6e056d2

Please sign in to comment.