mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 15:12:15 +03:00
Send conversion method suggestions (#7857)
close #7320
Changelog:
- update: enable conversion suggestions
- fix: conversion suggestion building
- fix: conversion suggestion types
- fix: conversion JSON-RPC representation
# Important Notes
For example, the [`Day_Of_Week_From`](5150c14afd/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Day_Of_Week_From.enso
) conversion is sent as
```json
{
"type":"Add",
"id":32,
"suggestion":{
"type":"method",
"module":"Standard.Base.Data.Time.Day_Of_Week_From",
"name":"from",
"arguments":[
{
"name":"that",
"reprType":"Standard.Base.Data.Numbers.Integer",
"isSuspended":false,
"hasDefault":false,
"defaultValue":null,
"tagValues":null
},
{
"name":"first_day",
"reprType":"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week",
"isSuspended":false,
"hasDefault":true,
"defaultValue":"Day_Of_Week.Sunday",
"tagValues":[
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Sunday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Monday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Tuesday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Wednesday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Thursday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Friday",
"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week.Saturday"
]
},
{
"name":"start_at_zero",
"reprType":"Standard.Base.Data.Boolean.Boolean",
"isSuspended":false,
"hasDefault":true,
"defaultValue":"False",
"tagValues":[
"Standard.Base.Data.Boolean.Boolean.True",
"Standard.Base.Data.Boolean.Boolean.False"
]
}
],
"selfType":"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week",
"returnType":"Standard.Base.Data.Time.Day_Of_Week.Day_Of_Week",
"isStatic":false,
"documentation":" Convert from an integer to a Day_Of_Week\n\nArguments:\n- `that`: The first day of the week.\n- `first_day`: The first day of the week.\n- `start_at_zero`: If True, first day of the week is 0 otherwise is 1.",
"annotations":[
]
}
}
```
This commit is contained in:
parent
b0a5ac2c19
commit
c88765d259
@ -126,19 +126,12 @@ object SearchProtocol {
|
||||
|
||||
private def conversionToMethod(
|
||||
conversion: Suggestion.Conversion
|
||||
): Suggestion.DefinedMethod = {
|
||||
val arg = Suggestion.Argument(
|
||||
Suggestion.Kind.Conversion.From,
|
||||
conversion.selfType,
|
||||
false,
|
||||
false,
|
||||
None
|
||||
)
|
||||
): Suggestion.DefinedMethod =
|
||||
Suggestion.DefinedMethod(
|
||||
conversion.externalId,
|
||||
conversion.module,
|
||||
conversion.name,
|
||||
arg +: conversion.arguments,
|
||||
conversion.arguments,
|
||||
conversion.returnType,
|
||||
conversion.returnType,
|
||||
conversion.isStatic,
|
||||
@ -146,7 +139,6 @@ object SearchProtocol {
|
||||
conversion.annotations,
|
||||
conversion.reexport
|
||||
)
|
||||
}
|
||||
|
||||
private def getterToMethod(
|
||||
getter: Suggestion.Getter
|
||||
|
@ -159,21 +159,24 @@ final class SuggestionBuilder[A: IndexedSource](
|
||||
|
||||
case definition.Method
|
||||
.Conversion(
|
||||
Name.MethodReference(_, _, _, _, _),
|
||||
Name.Literal(sourceTypeName, _, _, _, _),
|
||||
Name.MethodReference(typePtr, _, _, _, _),
|
||||
_,
|
||||
Function.Lambda(args, body, _, _, _, _),
|
||||
_,
|
||||
_,
|
||||
_
|
||||
) if ConversionsEnabled =>
|
||||
val typeSignature = ir.getMetadata(TypeSignatures)
|
||||
) =>
|
||||
val selfType = typePtr.flatMap { typePointer =>
|
||||
typePointer
|
||||
.getMetadata(MethodDefinitions)
|
||||
.map(_.target.qualifiedName)
|
||||
}
|
||||
val conversion = buildConversion(
|
||||
body.getExternalId,
|
||||
module,
|
||||
selfType,
|
||||
args,
|
||||
sourceTypeName,
|
||||
doc,
|
||||
typeSignature
|
||||
doc
|
||||
)
|
||||
go(tree += Tree.Node(conversion, Vector()), scope)
|
||||
|
||||
@ -286,20 +289,25 @@ final class SuggestionBuilder[A: IndexedSource](
|
||||
private def buildConversion(
|
||||
externalId: Option[IR.ExternalId],
|
||||
module: QualifiedName,
|
||||
selfType: Option[QualifiedName],
|
||||
args: Seq[DefinitionArgument],
|
||||
sourceTypeName: String,
|
||||
doc: Option[String],
|
||||
typeSignature: Option[TypeSignatures.Metadata]
|
||||
doc: Option[String]
|
||||
): Suggestion.Conversion = {
|
||||
val typeSig = buildTypeSignatureFromMetadata(typeSignature)
|
||||
val (methodArgs, returnTypeDef) =
|
||||
buildFunctionArguments(args, typeSig)
|
||||
val methodArgs =
|
||||
args.map { arg =>
|
||||
buildTypeSignatureFromMetadata(
|
||||
arg.getMetadata(TypeSignatures)
|
||||
).headOption
|
||||
.map(buildTypedArgument(arg, _))
|
||||
.getOrElse(buildArgument(arg))
|
||||
}.tail
|
||||
|
||||
Suggestion.Conversion(
|
||||
externalId = externalId,
|
||||
module = module.toString,
|
||||
arguments = methodArgs,
|
||||
selfType = sourceTypeName,
|
||||
returnType = buildReturnType(returnTypeDef),
|
||||
selfType = methodArgs.head.reprType,
|
||||
returnType = selfType.fold(Any)(_.toString),
|
||||
documentation = doc
|
||||
)
|
||||
}
|
||||
@ -725,7 +733,9 @@ final class SuggestionBuilder[A: IndexedSource](
|
||||
expr match {
|
||||
case Literal.Number(_, value, _, _, _) => Some(value)
|
||||
case Literal.Text(text, _, _, _) => Some(text)
|
||||
case _ => None
|
||||
case Application.Prefix(name, path, _, _, _, _) =>
|
||||
Some(path.map(_.value.showCode()).mkString(".") + "." + name.showCode())
|
||||
case other => Some(other.showCode())
|
||||
}
|
||||
|
||||
/** Build scope from the location. */
|
||||
@ -745,9 +755,6 @@ final class SuggestionBuilder[A: IndexedSource](
|
||||
|
||||
object SuggestionBuilder {
|
||||
|
||||
/** TODO[DB] enable conversions when they get the runtime support. */
|
||||
private val ConversionsEnabled: Boolean = false
|
||||
|
||||
/** Creates the suggestion builder for a module.
|
||||
*
|
||||
* @param module the module to index
|
||||
|
@ -857,14 +857,14 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
}
|
||||
|
||||
"build conversion method for simple type" in {
|
||||
pending
|
||||
|
||||
val code =
|
||||
"""type MyAtom a
|
||||
"""import Standard.Base.Data.Numbers
|
||||
|
|
||||
|type Foo
|
||||
| Value foo
|
||||
|
|
||||
|## My conversion
|
||||
|MyAtom.from : Number -> MyAtom
|
||||
|MyAtom.from a = MyAtom a
|
||||
|Foo.from (that:Numbers.Number) = Foo.Value a
|
||||
|""".stripMargin
|
||||
val module = code.preprocessModule
|
||||
|
||||
@ -873,31 +873,42 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
ModuleNode,
|
||||
Tree.Node(
|
||||
Suggestion.Type(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "MyType",
|
||||
params = Seq(
|
||||
Suggestion
|
||||
.Argument("a", SuggestionBuilder.Any, false, false, None)
|
||||
),
|
||||
returnType = "Unnamed.Test.MyType",
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "Foo",
|
||||
params = Seq(),
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
parentType = Some(SuggestionBuilder.Any),
|
||||
documentation = None
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.DefinedMethod(
|
||||
Suggestion.Constructor(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "a",
|
||||
name = "Value",
|
||||
arguments = Seq(
|
||||
Suggestion
|
||||
.Argument("foo", SuggestionBuilder.Any, false, false, None)
|
||||
),
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Getter(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "foo",
|
||||
arguments = List(
|
||||
Suggestion
|
||||
.Argument("self", "Unnamed.Test.MyType", false, false, None)
|
||||
.Argument("self", "Unnamed.Test.Foo", false, false, None)
|
||||
),
|
||||
selfType = "Unnamed.Test.MyType",
|
||||
selfType = "Unnamed.Test.Foo",
|
||||
returnType = SuggestionBuilder.Any,
|
||||
isStatic = false,
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
@ -908,10 +919,16 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
arguments = Seq(
|
||||
Suggestion.Argument("a", "Number", false, false, None)
|
||||
Suggestion.Argument(
|
||||
"that",
|
||||
"Standard.Base.Data.Numbers.Number",
|
||||
false,
|
||||
false,
|
||||
None
|
||||
)
|
||||
),
|
||||
returnType = "Unnamed.Test.MyType",
|
||||
selfType = "Number",
|
||||
selfType = "Standard.Base.Data.Numbers.Number",
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = Some(" My conversion")
|
||||
),
|
||||
Vector()
|
||||
@ -920,21 +937,14 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
)
|
||||
}
|
||||
|
||||
"build conversion method for complex type" in {
|
||||
pending
|
||||
"build conversion method with extra arguments" in {
|
||||
val code =
|
||||
"""type MyMaybe
|
||||
| Some a
|
||||
| None
|
||||
"""import Standard.Base.Data.Numbers
|
||||
|
|
||||
|type New
|
||||
| Newtype x
|
||||
|type Foo
|
||||
| Value foo bar
|
||||
|
|
||||
|## My conversion method
|
||||
|New.from : MyMaybe -> New
|
||||
|New.from opt = case opt of
|
||||
| Some a -> Newtype a
|
||||
| None -> Newtype 0
|
||||
|Foo.from (that:Numbers.Number) other=1 = Foo.Value that other
|
||||
|""".stripMargin
|
||||
val module = code.preprocessModule
|
||||
|
||||
@ -945,9 +955,9 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
Suggestion.Type(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "MyMaybe",
|
||||
name = "Foo",
|
||||
params = Seq(),
|
||||
returnType = "Unnamed.Test.MyMaybe",
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
parentType = Some(SuggestionBuilder.Any),
|
||||
documentation = None
|
||||
),
|
||||
@ -957,85 +967,46 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
Suggestion.Constructor(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "Some",
|
||||
name = "Value",
|
||||
arguments = Seq(
|
||||
Suggestion
|
||||
.Argument("a", SuggestionBuilder.Any, false, false, None)
|
||||
.Argument("foo", SuggestionBuilder.Any, false, false, None),
|
||||
Suggestion
|
||||
.Argument("bar", SuggestionBuilder.Any, false, false, None)
|
||||
),
|
||||
returnType = "Unnamed.Test.MyMaybe",
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.DefinedMethod(
|
||||
Suggestion.Getter(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "a",
|
||||
name = "foo",
|
||||
arguments = List(
|
||||
Suggestion
|
||||
.Argument("self", "Unnamed.Test.MyMaybe", false, false, None)
|
||||
.Argument("self", "Unnamed.Test.Foo", false, false, None)
|
||||
),
|
||||
selfType = "Unnamed.Test.MyMaybe",
|
||||
selfType = "Unnamed.Test.Foo",
|
||||
returnType = SuggestionBuilder.Any,
|
||||
isStatic = false,
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Constructor(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "None",
|
||||
arguments = Seq(),
|
||||
returnType = "Unnamed.Test.None",
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Type(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "New",
|
||||
params = Seq(),
|
||||
returnType = "Unnamed.Test.New",
|
||||
parentType = Some(SuggestionBuilder.Any),
|
||||
documentation = None
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Constructor(
|
||||
Suggestion.Getter(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "Newtype",
|
||||
arguments = Seq(
|
||||
Suggestion
|
||||
.Argument("x", SuggestionBuilder.Any, false, false, None)
|
||||
),
|
||||
returnType = "Unnamed.Test.New",
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.DefinedMethod(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "x",
|
||||
name = "bar",
|
||||
arguments = List(
|
||||
Suggestion
|
||||
.Argument("self", "Unnamed.Test.New", false, false, None)
|
||||
.Argument("self", "Unnamed.Test.Foo", false, false, None)
|
||||
),
|
||||
selfType = "Unnamed.Test.New",
|
||||
selfType = "Unnamed.Test.Foo",
|
||||
returnType = SuggestionBuilder.Any,
|
||||
isStatic = false,
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
@ -1046,12 +1017,138 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
arguments = Seq(
|
||||
Suggestion.Argument(
|
||||
"that",
|
||||
"Standard.Base.Data.Numbers.Number",
|
||||
false,
|
||||
false,
|
||||
None
|
||||
),
|
||||
Suggestion
|
||||
.Argument("opt", "Unnamed.Test.MyMaybe", false, false, None)
|
||||
.Argument(
|
||||
"other",
|
||||
SuggestionBuilder.Any,
|
||||
false,
|
||||
true,
|
||||
Some("1")
|
||||
)
|
||||
),
|
||||
returnType = "Unnamed.Test.MyType",
|
||||
selfType = "Unnamed.Test.MyMaybe",
|
||||
documentation = Some(" My conversion method")
|
||||
selfType = "Standard.Base.Data.Numbers.Number",
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = None
|
||||
),
|
||||
Vector()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"build conversion method with extra typed arguments" in {
|
||||
val code =
|
||||
"""import Standard.Base.Data.Numbers
|
||||
|from Standard.Base.Data.Boolean import Boolean
|
||||
|
|
||||
|type Foo
|
||||
| Value foo bar
|
||||
|
|
||||
|Foo.from (that:Numbers.Number) (other:Boolean=Boolean.True) = Foo.Value that other
|
||||
|""".stripMargin
|
||||
val module = code.preprocessModule
|
||||
|
||||
build(code, module) shouldEqual Tree.Root(
|
||||
Vector(
|
||||
ModuleNode,
|
||||
Tree.Node(
|
||||
Suggestion.Type(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "Foo",
|
||||
params = Seq(),
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
parentType = Some(SuggestionBuilder.Any),
|
||||
documentation = None
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Constructor(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "Value",
|
||||
arguments = Seq(
|
||||
Suggestion
|
||||
.Argument("foo", SuggestionBuilder.Any, false, false, None),
|
||||
Suggestion
|
||||
.Argument("bar", SuggestionBuilder.Any, false, false, None)
|
||||
),
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Getter(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "foo",
|
||||
arguments = List(
|
||||
Suggestion
|
||||
.Argument("self", "Unnamed.Test.Foo", false, false, None)
|
||||
),
|
||||
selfType = "Unnamed.Test.Foo",
|
||||
returnType = SuggestionBuilder.Any,
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Getter(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
name = "bar",
|
||||
arguments = List(
|
||||
Suggestion
|
||||
.Argument("self", "Unnamed.Test.Foo", false, false, None)
|
||||
),
|
||||
selfType = "Unnamed.Test.Foo",
|
||||
returnType = SuggestionBuilder.Any,
|
||||
documentation = None,
|
||||
annotations = Seq()
|
||||
),
|
||||
Vector()
|
||||
),
|
||||
Tree.Node(
|
||||
Suggestion.Conversion(
|
||||
externalId = None,
|
||||
module = "Unnamed.Test",
|
||||
arguments = Seq(
|
||||
Suggestion.Argument(
|
||||
"that",
|
||||
"Standard.Base.Data.Numbers.Number",
|
||||
false,
|
||||
false,
|
||||
None
|
||||
),
|
||||
Suggestion
|
||||
.Argument(
|
||||
"other",
|
||||
"Standard.Base.Data.Boolean.Boolean",
|
||||
false,
|
||||
true,
|
||||
Some("Boolean.True"),
|
||||
Some(
|
||||
List(
|
||||
"Standard.Base.Data.Boolean.Boolean.True",
|
||||
"Standard.Base.Data.Boolean.Boolean.False"
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
selfType = "Standard.Base.Data.Numbers.Number",
|
||||
returnType = "Unnamed.Test.Foo",
|
||||
documentation = None
|
||||
),
|
||||
Vector()
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user