Skip to content

Commit

Permalink
Sum type info in suggestions DB (#3422)
Browse files Browse the repository at this point in the history
A draft of simple changes to the compiler to expose sum type information. Doesn't break the stdlib & at the same time allows for dropdowns. This is still broken, for example it doesn't handle exporting/importing types, only ones defined in the same module as the signature. Still, seems like a step in the right direction – please provide feedback.

# Important Notes
I've decided to make the variant info part of the type, not the argument – it is a property of the type logically.

Also, I've pushed it as far as I'm comfortable – i.e. to the `SuggestionHandler` – I have no idea if this is enough to show in IDE? cc @4e6
  • Loading branch information
kustosz committed May 5, 2022
1 parent 3ab2c8f commit ce6a97e
Show file tree
Hide file tree
Showing 24 changed files with 416 additions and 152 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
- [Fixed execution of defaulted arguments of Atom Constructors][3358]
- [Converting Enso Date to java.time.LocalDate and back][3374]
- [Functions with all-defaulted arguments now execute automatically][3414]
- [Provide `tagValues` for function arguments in the language server][3422]
- [Delay construction of Truffle nodes to speed initialization][3429]
- [Frgaal compiler integration to allow for latest Java constructs][3421]

Expand All @@ -202,6 +203,7 @@
[3412]: https://github.com/enso-org/enso/pull/3412
[3414]: https://github.com/enso-org/enso/pull/3414
[3417]: https://github.com/enso-org/enso/pull/3417
[3422]: https://github.com/enso-org/enso/pull/3422
[3429]: https://github.com/enso-org/enso/pull/3429
[3421]: https://github.com/enso-org/enso/pull/3421

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
}
],
"returnType" : "MyAtom",
Expand Down Expand Up @@ -141,14 +142,16 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "MyType",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "foo",
"reprType" : "Number",
"isSuspended" : false,
"hasDefault" : true,
"defaultValue" : "42"
"defaultValue" : "42",
"tagValues" : null
}
],
"selfType" : "MyType",
Expand Down Expand Up @@ -224,21 +227,24 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "b",
"reprType" : "Any",
"isSuspended" : true,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "c",
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : true,
"defaultValue" : "C"
"defaultValue" : "C",
"tagValues" : null
}
],
"returnType" : "IO",
Expand Down Expand Up @@ -356,21 +362,24 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "b",
"reprType" : "Any",
"isSuspended" : true,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "c",
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : true,
"defaultValue" : "C"
"defaultValue" : "C",
"tagValues" : null
}
],
"returnType" : "IO",
Expand Down Expand Up @@ -398,7 +407,8 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "Any",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
}
],
"returnType" : "MyAtom",
Expand Down Expand Up @@ -461,14 +471,16 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "MyType",
"isSuspended" : false,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
},
{
"name" : "foo",
"reprType" : "Number",
"isSuspended" : false,
"hasDefault" : true,
"defaultValue" : "42"
"defaultValue" : "42",
"tagValues" : null
}
],
"selfType" : "MyType",
Expand Down Expand Up @@ -572,7 +584,8 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
"reprType" : "Any",
"isSuspended" : true,
"hasDefault" : false,
"defaultValue" : null
"defaultValue" : null,
"tagValues" : null
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ object Suggestion {
reprType: String,
isSuspended: Boolean,
hasDefault: Boolean,
defaultValue: Option[String]
defaultValue: Option[String],
tagValues: Option[Seq[String]] = None
) extends ToLogString {

/** @inheritdoc */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ sealed trait Tree[+A] {
final def map[B](f: A => B): Tree[B] =
Tree.map(this)(f)

/** Finds the first element of the tree for which the given partial function
* is defined, and applies the partial function to it.
*
* @param f the partial function to apply
* @return the result of running `f` on the first element it's defined for.
*/
@JsonIgnore
final def collectFirst[B](f: PartialFunction[A, B]): Option[B] =
Tree.collectFirst(this)(f)

/** Selects all elements which satisfy a predicate.
*
* @param p the predicate used to test elements
Expand Down Expand Up @@ -208,6 +218,22 @@ object Tree {
Node(f(a), cx.map(mapNode(_)(f)))
}

private def collectFirst[A, B](
tree: Tree[A]
)(f: PartialFunction[A, B]): Option[B] = {
def collectFirstNode(node: Tree.Node[A]): Option[B] = {
if (f.isDefinedAt(node.element)) {
Some(f(node.element))
} else {
node.children.collectFirst((collectFirstNode _).unlift)
}
}
tree match {
case Root(c) => c.collectFirst((collectFirstNode _).unlift)
case n: Node[A] => collectFirstNode(n)
}
}

private def filter[A](tree: Tree[A])(p: A => Boolean): Tree[A] = {
def filterNode(node: Tree.Node[A]): Option[Tree.Node[A]] = {
val childrenFiltered = node.children.flatMap(filterNode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class RuntimeStubsGenerator() {
BindingAnalysis,
"Non-parsed module used in stubs generator"
)
localBindings.types.foreach { tp =>
localBindings.constructors.foreach { tp =>
val constructor = new AtomConstructor(tp.name, scope)
scope.registerConstructor(constructor)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,22 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
resolvedName match {
case BindingsMap.ResolvedModule(module) =>
Some(module.getName)
case BindingsMap.ResolvedConstructor(module, cons) =>
Some(module.getName.createChild(cons.name))
case cons: BindingsMap.ResolvedConstructor =>
Some(cons.qualifiedName)
case _ =>
None
}
}

private def buildResolvedUnionTypeName(
resolvedName: BindingsMap.ResolvedTypeName
): Option[TypeArg] = resolvedName match {
case tp: BindingsMap.ResolvedType =>
Some(TypeArg.Sum(tp.qualifiedName, tp.getVariants.map(_.qualifiedName)))
case other: BindingsMap.ResolvedName =>
buildResolvedTypeName(other).map(TypeArg.Value)
}

/** Build type signature from the ir metadata.
*
* @param typeSignature the type signature metadata
Expand Down Expand Up @@ -380,19 +389,18 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
args :++ arg
case IR.Function.Lambda(List(targ), body, _, _, _, _) =>
val typeName = targ.name.name
val qualifiedTypeName = resolveTypeName(bindings, typeName)
.getOrElse(QualifiedName.simpleName(typeName))
val tdef = TypeArg.Value(qualifiedTypeName)
val tdef = resolveTypeName(bindings, typeName)
.getOrElse(TypeArg.Value(QualifiedName.simpleName(typeName)))
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)
.getOrElse(QualifiedName.simpleName(typeName))
args :+ TypeArg.Value(qualifiedTypeName)
val tdef = resolveTypeName(bindings, typeName)
.getOrElse(TypeArg.Value(QualifiedName.simpleName(typeName)))
args :+ tdef
case _ =>
args
}
Expand All @@ -415,10 +423,10 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
private def resolveTypeName(
bindings: Option[BindingAnalysis.Metadata],
name: String
): Option[QualifiedName] = {
): Option[TypeArg] = {
bindings
.flatMap(_.resolveUppercaseName(name).toOption)
.flatMap(buildResolvedTypeName)
.flatMap(_.resolveTypeName(name).toOption)
.flatMap(buildResolvedUnionTypeName)
}

/** Build arguments of a method.
Expand Down Expand Up @@ -521,7 +529,11 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
reprType = buildTypeArgumentName(targ),
isSuspended = varg.suspended,
hasDefault = varg.defaultValue.isDefined,
defaultValue = varg.defaultValue.flatMap(buildDefaultValue)
defaultValue = varg.defaultValue.flatMap(buildDefaultValue),
tagValues = targ match {
case TypeArg.Sum(_, variants) => Some(variants.map(_.toString))
case _ => None
}
)

/** Build the name of type argument.
Expand Down Expand Up @@ -549,6 +561,7 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
val argsList = args.map(go(_, level + 1)).mkString(" ")
val typeName = s"$funText $argsList"
if (level > 0) s"($typeName)" else typeName
case TypeArg.Sum(n, _) => n.toString
}

go(targ, 0)
Expand Down Expand Up @@ -639,6 +652,13 @@ object SuggestionBuilder {
sealed private trait TypeArg
private object TypeArg {

/** A sum type – one of many possible options.
* @param name the qualified name of the type.
* @param variants the qualified names of constituent atoms.
*/
case class Sum(name: QualifiedName, variants: Seq[QualifiedName])
extends TypeArg

/** Type with the name, like `A`.
*
* @param name the name of the type
Expand Down
Loading

0 comments on commit ce6a97e

Please sign in to comment.