mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-03-15 19:50:51 +00:00
fix(lsp): Go-to-definition for used types (LNG-345) (#1128)
This commit is contained in:
parent
faf5b8071f
commit
35db82c767
@ -1,29 +1,13 @@
|
|||||||
aqua Job declares *
|
aqua Job declares *
|
||||||
|
|
||||||
export aaa, bbb
|
use "declare.aqua"
|
||||||
|
|
||||||
data Peer:
|
export timeout
|
||||||
id: string
|
|
||||||
|
|
||||||
func aaa() -> Peer:
|
data Worker:
|
||||||
peer1 = Peer(id = "123")
|
field: string
|
||||||
peer2 = Peer(id = peer1.id)
|
|
||||||
<- peer2
|
|
||||||
|
|
||||||
data BrokenStruct:
|
func timeout() -> Worker:
|
||||||
fff: UnknownType
|
w <- AquaName.getWorker()
|
||||||
|
a = w.host_id
|
||||||
alias BrokenAlias: str3ng
|
<- w
|
||||||
|
|
||||||
ability BrokenAbility:
|
|
||||||
fff: str4ng
|
|
||||||
|
|
||||||
const BROKEN_CONST = UNKNOWN_CONST
|
|
||||||
|
|
||||||
func bbb() -> string:
|
|
||||||
<- 323
|
|
||||||
|
|
||||||
func ccc() -> Peer:
|
|
||||||
peer1 = Peer(id = "123")
|
|
||||||
peer2 = Peer(id = peer1.id)
|
|
||||||
<- peer2
|
|
@ -1,15 +1,8 @@
|
|||||||
aqua DeclareModule declares decl_foo, decl_bar, SuperFoo, DECLARE_CONST, DECLARE_CONST2
|
aqua AquaName declares getWorker, Worker
|
||||||
export SuperFoo
|
|
||||||
|
|
||||||
const DECLARE_CONST = "declare_const"
|
data Worker:
|
||||||
const DECLARE_CONST2 = "declare_const2"
|
host_id: string
|
||||||
|
|
||||||
service SuperFoo("super_foo"):
|
func getWorker() -> Worker:
|
||||||
small_foo() -> string
|
<- Worker(host_id = "")
|
||||||
|
|
||||||
func decl_foo() -> string:
|
|
||||||
res1 <- SuperFoo.small_foo()
|
|
||||||
<- res1
|
|
||||||
|
|
||||||
func decl_bar() -> string:
|
|
||||||
<- DECLARE_CONST
|
|
@ -23,6 +23,12 @@ class AquaLSPSpec extends AnyFlatSpec with Matchers with Inside {
|
|||||||
str.r.findAllMatchIn(code).toList.lift(position).map(r => (r.start, r.end))
|
str.r.findAllMatchIn(code).toList.lift(position).map(r => (r.start, r.end))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension [T](o: Option[T]) {
|
||||||
|
|
||||||
|
def tapNone(f: => Unit): Option[T] =
|
||||||
|
o.orElse { f; None }
|
||||||
|
}
|
||||||
|
|
||||||
extension (c: LspContext[Span.S]) {
|
extension (c: LspContext[Span.S]) {
|
||||||
|
|
||||||
def checkLocations(
|
def checkLocations(
|
||||||
@ -34,12 +40,14 @@ class AquaLSPSpec extends AnyFlatSpec with Matchers with Inside {
|
|||||||
fieldOrSynonym: Option[String] = None
|
fieldOrSynonym: Option[String] = None
|
||||||
): Boolean = {
|
): Boolean = {
|
||||||
(for {
|
(for {
|
||||||
defPos <- getByPosition(defCode, name, defPosition)
|
defPos <- getByPosition(defCode, name, defPosition).tapNone(
|
||||||
|
fail(s"Didn't find definition of '$name'")
|
||||||
|
)
|
||||||
usePos <- getByPosition(
|
usePos <- getByPosition(
|
||||||
useCode.getOrElse(defCode),
|
useCode.getOrElse(defCode),
|
||||||
fieldOrSynonym.getOrElse(name),
|
fieldOrSynonym.getOrElse(name),
|
||||||
usePosition
|
usePosition
|
||||||
)
|
).tapNone(fail(s"Didn't find usage of '$name'"))
|
||||||
} yield {
|
} yield {
|
||||||
val (defStart, defEnd) = defPos
|
val (defStart, defEnd) = defPos
|
||||||
val (useStart, useEnd) = usePos
|
val (useStart, useEnd) = usePos
|
||||||
@ -520,6 +528,56 @@ class AquaLSPSpec extends AnyFlatSpec with Matchers with Inside {
|
|||||||
res.checkLocations("someString", 1, 3, firstImport, Some(main)) shouldBe true
|
res.checkLocations("someString", 1, 3, firstImport, Some(main)) shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it should "return right tokens in 'use'd structures" in {
|
||||||
|
val main =
|
||||||
|
"""aqua Job declares *
|
||||||
|
|
|
||||||
|
|use "declare.aqua"
|
||||||
|
|
|
||||||
|
|export timeout
|
||||||
|
|
|
||||||
|
|func timeout() -> string:
|
||||||
|
| w <- AquaName.getWorker()
|
||||||
|
| a = w.host_id
|
||||||
|
| ab = AquaName.SomeAbility(getWrk = AquaName.getWorker, someField = "123")
|
||||||
|
| c = ab.getWrk()
|
||||||
|
| d = ab.someField
|
||||||
|
| <- a
|
||||||
|
|""".stripMargin
|
||||||
|
val src = Map(
|
||||||
|
"index.aqua" -> main
|
||||||
|
)
|
||||||
|
|
||||||
|
val firstImport =
|
||||||
|
"""aqua AquaName declares getWorker, Worker, SomeAbility
|
||||||
|
|
|
||||||
|
|data Worker:
|
||||||
|
| host_id: string
|
||||||
|
|
|
||||||
|
|ability SomeAbility:
|
||||||
|
| getWrk() -> Worker
|
||||||
|
| someField: string
|
||||||
|
|
|
||||||
|
|func getWorker() -> Worker:
|
||||||
|
| <- Worker(host_id = "")
|
||||||
|
|
|
||||||
|
|""".stripMargin
|
||||||
|
|
||||||
|
val imports = Map(
|
||||||
|
"declare.aqua" ->
|
||||||
|
firstImport
|
||||||
|
)
|
||||||
|
|
||||||
|
val res = compile(src, imports).toOption.get.values.head
|
||||||
|
|
||||||
|
res.errors shouldBe empty
|
||||||
|
res.checkLocations("host_id", 0, 0, firstImport, Some(main)) shouldBe true
|
||||||
|
res.checkLocations("getWorker", 1, 0, firstImport, Some(main)) shouldBe true
|
||||||
|
res.checkLocations("getWorker", 1, 0, firstImport) shouldBe true
|
||||||
|
res.checkLocations("getWrk", 0, 1, firstImport, Some(main)) shouldBe true
|
||||||
|
res.checkLocations("someField", 0, 1, firstImport, Some(main)) shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
it should "return right tokens for multiple abilities" in {
|
it should "return right tokens for multiple abilities" in {
|
||||||
val main =
|
val main =
|
||||||
"""aqua Import declares *
|
"""aqua Import declares *
|
||||||
|
@ -7,6 +7,8 @@ case class ConstantRaw(name: String, value: ValueRaw, allowOverrides: Boolean) e
|
|||||||
override def rename(s: String): RawPart = copy(name = s)
|
override def rename(s: String): RawPart = copy(name = s)
|
||||||
|
|
||||||
override def rawPartType: Type = value.`type`
|
override def rawPartType: Type = value.`type`
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart = this
|
||||||
}
|
}
|
||||||
|
|
||||||
object ConstantRaw {
|
object ConstantRaw {
|
||||||
|
@ -7,4 +7,6 @@ case class ErroredPart(name: String) extends RawPart {
|
|||||||
override def rawPartType: Type = BottomType
|
override def rawPartType: Type = BottomType
|
||||||
|
|
||||||
override def rename(s: String): RawPart = copy(name = s)
|
override def rename(s: String): RawPart = copy(name = s)
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart = this
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ trait RawPart extends Raw {
|
|||||||
def rawPartType: Type
|
def rawPartType: Type
|
||||||
|
|
||||||
def rename(s: String): RawPart
|
def rename(s: String): RawPart
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart
|
||||||
}
|
}
|
||||||
|
|
||||||
object RawPart {
|
object RawPart {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package aqua.raw
|
package aqua.raw
|
||||||
|
|
||||||
import aqua.types.ServiceType
|
import aqua.types.{ServiceType, Type}
|
||||||
import aqua.raw.value.ValueRaw
|
import aqua.raw.value.ValueRaw
|
||||||
|
|
||||||
case class ServiceRaw(
|
case class ServiceRaw(
|
||||||
@ -12,4 +12,5 @@ case class ServiceRaw(
|
|||||||
|
|
||||||
override def rename(s: String): RawPart = copy(name = s)
|
override def rename(s: String): RawPart = copy(name = s)
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart = copy(`type` = Type.addAbilityNameService(s, `type`))
|
||||||
}
|
}
|
||||||
|
@ -6,4 +6,6 @@ case class TypeRaw(name: String, `type`: Type) extends RawPart {
|
|||||||
override def rename(s: String): RawPart = copy(name = s)
|
override def rename(s: String): RawPart = copy(name = s)
|
||||||
|
|
||||||
override def rawPartType: Type = `type`
|
override def rawPartType: Type = `type`
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart = copy(`type` = Type.addAbilityName(s, `type`))
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ case class FuncRaw(
|
|||||||
) extends RawPart {
|
) extends RawPart {
|
||||||
override def rename(s: String): RawPart = copy(name = s)
|
override def rename(s: String): RawPart = copy(name = s)
|
||||||
|
|
||||||
|
def addAbilityName(s: String): RawPart = copy(arrow = arrow.copy(`type` = Type.addAbilityNameArrow(s, arrow.`type`)))
|
||||||
|
|
||||||
override def rawPartType: Type = arrow.`type`
|
override def rawPartType: Type = arrow.`type`
|
||||||
|
|
||||||
// vars that we capture from external space (outer functions, etc)
|
// vars that we capture from external space (outer functions, etc)
|
||||||
|
@ -133,6 +133,7 @@ case class PropertyToken[F[_]: Comonad](
|
|||||||
case IntoField(name) => name.extract.some
|
case IntoField(name) => name.extract.some
|
||||||
case _ => none
|
case _ => none
|
||||||
}.map { props =>
|
}.map { props =>
|
||||||
|
// TODO: this loses the correct token location
|
||||||
val typeName = name
|
val typeName = name
|
||||||
.rename(
|
.rename(
|
||||||
(name.value +: props).mkString(".")
|
(name.value +: props).mkString(".")
|
||||||
|
@ -130,7 +130,10 @@ object Picker {
|
|||||||
override def allNames(ctx: RawContext): Set[String] = ctx.allNames
|
override def allNames(ctx: RawContext): Set[String] = ctx.allNames
|
||||||
|
|
||||||
override def setAbility(ctx: RawContext, name: String, ctxAb: RawContext): RawContext =
|
override def setAbility(ctx: RawContext, name: String, ctxAb: RawContext): RawContext =
|
||||||
ctx.copy(abilities = Map(name -> ctxAb))
|
ctx.copy(abilities = Map(name -> ctxAb.copy(parts = ctxAb.parts.map {
|
||||||
|
case (partContext, part) =>
|
||||||
|
(partContext, part.addAbilityName(name))
|
||||||
|
})))
|
||||||
|
|
||||||
// dummy
|
// dummy
|
||||||
override def setImportPaths(ctx: RawContext, importPaths: Map[String, String]): RawContext =
|
override def setImportPaths(ctx: RawContext, importPaths: Map[String, String]): RawContext =
|
||||||
|
@ -18,7 +18,6 @@ import cats.data.{NonEmptyList, OptionT}
|
|||||||
import cats.instances.list.*
|
import cats.instances.list.*
|
||||||
import cats.syntax.applicative.*
|
import cats.syntax.applicative.*
|
||||||
import cats.syntax.apply.*
|
import cats.syntax.apply.*
|
||||||
import cats.syntax.bifunctor.*
|
|
||||||
import cats.syntax.flatMap.*
|
import cats.syntax.flatMap.*
|
||||||
import cats.syntax.foldable.*
|
import cats.syntax.foldable.*
|
||||||
import cats.syntax.functor.*
|
import cats.syntax.functor.*
|
||||||
|
@ -57,6 +57,8 @@ sealed trait ProductType extends Type {
|
|||||||
|
|
||||||
def length: Int
|
def length: Int
|
||||||
|
|
||||||
|
def map(f: Type => Type): ProductType
|
||||||
|
|
||||||
def uncons: Option[(Type, ProductType)] = this match {
|
def uncons: Option[(Type, ProductType)] = this match {
|
||||||
case ConsType(t, pt) => Some(t -> pt)
|
case ConsType(t, pt) => Some(t -> pt)
|
||||||
case _ => None
|
case _ => None
|
||||||
@ -149,14 +151,20 @@ object ConsType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class LabeledConsType(label: String, `type`: Type, tail: ProductType) extends ConsType {
|
case class LabeledConsType(label: String, `type`: Type, tail: ProductType) extends ConsType {
|
||||||
|
def map(f: Type => Type): ProductType = copy(`type` = f(`type`), tail = tail.map(f))
|
||||||
|
|
||||||
override def toString: String = s"($label: " + `type` + s") :: $tail"
|
override def toString: String = s"($label: " + `type` + s") :: $tail"
|
||||||
}
|
}
|
||||||
|
|
||||||
case class UnlabeledConsType(`type`: Type, tail: ProductType) extends ConsType {
|
case class UnlabeledConsType(`type`: Type, tail: ProductType) extends ConsType {
|
||||||
|
def map(f: Type => Type): ProductType = copy(`type` = f(`type`), tail = tail.map(f))
|
||||||
|
|
||||||
override def toString: String = `type`.toString + s" :: $tail"
|
override def toString: String = `type`.toString + s" :: $tail"
|
||||||
}
|
}
|
||||||
|
|
||||||
object NilType extends ProductType {
|
object NilType extends ProductType {
|
||||||
|
def map(f: Type => Type): ProductType = this
|
||||||
|
|
||||||
override def toString: String = "∅"
|
override def toString: String = "∅"
|
||||||
|
|
||||||
override def isInhabited: Boolean = false
|
override def isInhabited: Boolean = false
|
||||||
@ -546,6 +554,56 @@ object Type {
|
|||||||
t.toString
|
t.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def addAbilityNameProduct(abName: String, t: ProductType): ProductType =
|
||||||
|
t.map(t => addAbilityName(abName, t))
|
||||||
|
|
||||||
|
def addAbilityNameArrow(abName: String, t: ArrowType): ArrowType = {
|
||||||
|
t.copy(
|
||||||
|
domain = addAbilityNameProduct(abName, t.domain),
|
||||||
|
codomain = addAbilityNameProduct(abName, t.codomain)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addAbilityNameData(abName: String, dt: DataType): DataType =
|
||||||
|
dt match {
|
||||||
|
case st @ StructType(name, fields) =>
|
||||||
|
st.copy(
|
||||||
|
name = AbilityType.fullName(abName, name),
|
||||||
|
fields = fields.map(Type.addAbilityName(abName, _))
|
||||||
|
)
|
||||||
|
case ot @ OptionType(el) => ot.copy(element = addAbilityNameData(abName, el))
|
||||||
|
case at @ ArrayType(el) => at.copy(element = addAbilityNameData(abName, el))
|
||||||
|
case t => t
|
||||||
|
}
|
||||||
|
|
||||||
|
def addAbilityNameService(abName: String, t: ServiceType): ServiceType = {
|
||||||
|
t.copy(
|
||||||
|
name = AbilityType.fullName(abName, t.name),
|
||||||
|
fields = t.fields.map(Type.addAbilityNameArrow(abName, _))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ability name to type names
|
||||||
|
def addAbilityName(abName: String, t: Type): Type = {
|
||||||
|
t match {
|
||||||
|
case at @ AbilityType(name, fields) =>
|
||||||
|
at.copy(
|
||||||
|
name = AbilityType.fullName(abName, name),
|
||||||
|
fields = fields.map(Type.addAbilityName(abName, _))
|
||||||
|
)
|
||||||
|
case st: ServiceType =>
|
||||||
|
addAbilityNameService(abName, st)
|
||||||
|
|
||||||
|
case at: ArrowType =>
|
||||||
|
addAbilityNameArrow(abName, at)
|
||||||
|
case st @ CanonStreamType(el) => st.copy(element = addAbilityNameData(abName, el))
|
||||||
|
case st @ StreamType(el) => st.copy(element = addAbilityNameData(abName, el))
|
||||||
|
case smt @ StreamMapType(el) => smt.copy(element = addAbilityNameData(abName, el))
|
||||||
|
case pt: ProductType => addAbilityNameProduct(abName, pt)
|
||||||
|
case t: DataType => addAbilityNameData(abName, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pretty print for Type
|
// pretty print for Type
|
||||||
given Show[Type] = {
|
given Show[Type] = {
|
||||||
case ArrayType(el) =>
|
case ArrayType(el) =>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user