Use autoscoping when constructing tag values of suggestion arguments (#9293)

This commit is contained in:
Dmitry Bushev 2024-04-08 12:39:49 +01:00 committed by GitHub
parent 8aef2146db
commit 1c4a927701
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 337 additions and 14 deletions

View File

@ -1,7 +1,6 @@
package org.enso.compiler.context
import org.enso.compiler.Compiler
import org.enso.compiler.context.CompilerContext
import org.enso.compiler.core.Implicits.AsMetadata
import org.enso.compiler.core.{ExternalID, IR}
import org.enso.compiler.core.ir.expression.{Application, Operator}
@ -640,25 +639,42 @@ final class SuggestionBuilder[A: IndexedSource](
isSuspended = varg.suspended,
hasDefault = varg.defaultValue.isDefined,
defaultValue = varg.defaultValue.map(buildDefaultValue),
tagValues = buildTagValues(targ)
tagValues = buildTagValues(targ, varg.ascribedType.nonEmpty)
)
/** Build tag values of type argument.
*
* @param targ the type argument
* @param hasTypeAscription if the type ascription was used in type definition
* @return the list of tag values
*/
private def buildTagValues(targ: TypeArg): Option[Seq[String]] = {
def go(arg: TypeArg): Seq[String] = arg match {
case TypeArg.Sum(_, List()) => Seq()
case TypeArg.Sum(_, variants) => variants.flatMap(go)
case TypeArg.Value(n) => Seq(n.toString)
case _ => Seq()
private def buildTagValues(
targ: TypeArg,
hasTypeAscription: Boolean
): Option[Seq[String]] = {
def mkUnqualified(name: QualifiedName): String =
name.item
def mkQualified(name: QualifiedName): String =
name.toString
def mkAutoScopeCall(name: String): String =
s"..$name"
def go(arg: TypeArg, useAutoScope: Boolean): Seq[String] = arg match {
case TypeArg.Sum(_, List()) => Seq()
case TypeArg.Sum(_, variants) =>
variants.flatMap(go(_, useAutoScope))
case TypeArg.Value(n) =>
Seq(if (useAutoScope) mkUnqualified(n) else mkQualified(n))
case _ => Seq()
}
targ match {
case s: TypeArg.Sum =>
val tagValues = go(s)
val tagItems = go(s, hasTypeAscription)
val canUseAutoScope =
hasTypeAscription && tagItems.distinct.length == tagItems.length
val tagValues =
if (canUseAutoScope) tagItems.map(mkAutoScopeCall)
else go(s, useAutoScope = false)
Option.unless(tagValues.isEmpty)(tagValues)
case _ => None

View File

@ -774,7 +774,7 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
|
|type Auto
|
|foo : Text | Boolean | Value | Auto -> Any
|foo : Text | Boolean | Value | Auto -> Value
|foo a = a
|""".stripMargin
val module = code.preprocessModule
@ -854,7 +854,314 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
)
),
selfType = "Unnamed.Test",
returnType = "Any",
returnType = "Unnamed.Test.Value",
isStatic = true,
documentation = None,
annotations = Seq()
),
Vector()
)
)
)
}
"build argument tag values from ascribed type" in {
val code =
"""type Value
| A
| B
|
|type Auto
|
|foo (a : Value | Auto) = a
|""".stripMargin
val module = code.preprocessModule
build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "Value",
params = Seq(),
returnType = "Unnamed.Test.Value",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "A",
arguments = Seq(),
returnType = "Unnamed.Test.Value",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "B",
arguments = Seq(),
returnType = "Unnamed.Test.Value",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "Auto",
params = Seq(),
returnType = "Unnamed.Test.Auto",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.DefinedMethod(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument(
"a",
"Unnamed.Test.Value | Unnamed.Test.Auto",
false,
false,
None,
Some(Seq("..A", "..B", "..Auto"))
)
),
selfType = "Unnamed.Test",
returnType = SuggestionBuilder.Any,
isStatic = true,
documentation = None,
annotations = Seq()
),
Vector()
)
)
)
}
"build argument tag values from ascribed type and type signature" in {
val code =
"""type Value
| A
| B
|
|type Auto
|
|foo : Value | Auto -> Value | Auto
|foo (a : Value | Auto) = a
|""".stripMargin
val module = code.preprocessModule
build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "Value",
params = Seq(),
returnType = "Unnamed.Test.Value",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "A",
arguments = Seq(),
returnType = "Unnamed.Test.Value",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "B",
arguments = Seq(),
returnType = "Unnamed.Test.Value",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "Auto",
params = Seq(),
returnType = "Unnamed.Test.Auto",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.DefinedMethod(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument(
"a",
"Unnamed.Test.Value | Unnamed.Test.Auto",
false,
false,
None,
Some(Seq("..A", "..B", "..Auto"))
)
),
selfType = "Unnamed.Test",
returnType = "Unnamed.Test.Value | Unnamed.Test.Auto",
isStatic = true,
documentation = None,
annotations = Seq()
),
Vector()
)
)
)
}
"build argument tag values checking if autoscoped constructors are distinct" in {
val code =
"""type T
| A
| B
|
|type K
| B
| C
|
|foo (a : T | K) = a
|""".stripMargin
val module = code.preprocessModule
build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "T",
params = Seq(),
returnType = "Unnamed.Test.T",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "A",
arguments = Seq(),
returnType = "Unnamed.Test.T",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "B",
arguments = Seq(),
returnType = "Unnamed.Test.T",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Type(
externalId = None,
module = "Unnamed.Test",
name = "K",
params = Seq(),
returnType = "Unnamed.Test.K",
parentType = Some(SuggestionBuilder.Any),
documentation = None
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "B",
arguments = Seq(),
returnType = "Unnamed.Test.K",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.Constructor(
externalId = None,
module = "Unnamed.Test",
name = "C",
arguments = Seq(),
returnType = "Unnamed.Test.K",
documentation = None,
annotations = Seq()
),
Vector()
),
Tree.Node(
Suggestion.DefinedMethod(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument(
"a",
"Unnamed.Test.T | Unnamed.Test.K",
false,
false,
None,
Some(
Seq(
"Unnamed.Test.T.A",
"Unnamed.Test.T.B",
"Unnamed.Test.K.B",
"Unnamed.Test.K.C"
)
)
)
),
selfType = "Unnamed.Test",
returnType = SuggestionBuilder.Any,
isStatic = true,
documentation = None,
annotations = Seq()
@ -1230,8 +1537,8 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
Some("Boolean.True"),
Some(
List(
"Standard.Base.Data.Boolean.Boolean.True",
"Standard.Base.Data.Boolean.Boolean.False"
"..True",
"..False"
)
)
)
@ -2333,7 +2640,7 @@ class SuggestionBuilderTest extends AnyWordSpecLike with Matchers {
false,
false,
None,
Some(Seq("Unnamed.Test.S.X", "Unnamed.Test.S.Y"))
Some(Seq("..X", "..Y"))
)
),
returnType = "Unnamed.Test.T",