mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-04-24 14:32:13 +00:00
fix(compiler): Use strict
to check types availability [LNG-334] (#1071)
This commit is contained in:
parent
f7194f0a54
commit
17fb77c40f
@ -1,92 +1,29 @@
|
||||
aqua A
|
||||
|
||||
export get_logs
|
||||
export main
|
||||
|
||||
service Op("op"):
|
||||
id(s1: string)
|
||||
identity(s: string) -> string
|
||||
alias SomeAlias: string
|
||||
|
||||
service MyOp("op"):
|
||||
id(s1: string)
|
||||
identity(s: string) -> string
|
||||
data NestedStruct:
|
||||
a: SomeAlias
|
||||
|
||||
func get_logs(a: string):
|
||||
if a == "sdf":
|
||||
streamA <- Op.identity("some serv")
|
||||
Op.id(streamA)
|
||||
streamA: *string
|
||||
streamA <- Op.identity("stream")
|
||||
data SomeStruct:
|
||||
al: SomeAlias
|
||||
nested: NestedStruct
|
||||
|
||||
-- ability WorkerJob:
|
||||
-- runOnSingleWorker(w: string) -> []string
|
||||
--
|
||||
-- func runJob(j: -> []string) -> []string:
|
||||
-- <- j()
|
||||
--
|
||||
-- func disjoint_run{WorkerJob}() -> -> []string:
|
||||
-- run = func () -> []string:
|
||||
-- r <- WorkerJob.runOnSingleWorker("a")
|
||||
-- <- r
|
||||
-- <- run
|
||||
--
|
||||
-- func empty() -> string:
|
||||
-- a = "empty"
|
||||
-- <- a
|
||||
--
|
||||
-- func lng317Bug() -> []string:
|
||||
--
|
||||
-- res: *string
|
||||
--
|
||||
-- outer = () -> string:
|
||||
-- <- empty()
|
||||
--
|
||||
-- clos = () -> -> []string:
|
||||
-- job2 = () -> []string:
|
||||
-- res <- outer()
|
||||
-- res <- MyOp.identity("identity")
|
||||
-- <- res
|
||||
-- <- job2
|
||||
-- worker_job = WorkerJob(runOnSingleWorker = clos())
|
||||
-- subnet_job <- disjoint_run{worker_job}()
|
||||
-- finalRes <- runJob(subnet_job)
|
||||
-- <- finalRes
|
||||
--
|
||||
-- ability Job:
|
||||
-- run(s: string) -> string
|
||||
--
|
||||
-- func disrun(getJob: -> Job) -> Job:
|
||||
-- j <- getJob()
|
||||
-- <- j
|
||||
--
|
||||
-- func lng325Bug() -> string:
|
||||
-- brokenStream: *string
|
||||
--
|
||||
-- job = () -> Job:
|
||||
-- run = (str: string) -> string:
|
||||
-- brokenStream <- MyOp.identity(str)
|
||||
-- <- "run"
|
||||
--
|
||||
-- <- Job(run = run)
|
||||
--
|
||||
-- subnetJob <- disrun(job)
|
||||
-- subnetJob.run("firstStream string")
|
||||
-- <- brokenStream!
|
||||
--
|
||||
-- func secondStream() -> string:
|
||||
-- brokenStream: *string
|
||||
--
|
||||
-- secondJob = () -> Job:
|
||||
-- secondRun = (str: string) -> string:
|
||||
-- brokenStream <- MyOp.identity(str)
|
||||
-- <- "run"
|
||||
--
|
||||
-- <- Job(run = secondRun)
|
||||
--
|
||||
-- subnetJob <- disrun(secondJob)
|
||||
-- subnetJob.run("secondStream string")
|
||||
-- <- brokenStream!
|
||||
--
|
||||
-- func lng325BugTwoFuncs() -> string, string:
|
||||
-- res1 <- lng325Bug()
|
||||
-- res2 <- secondStream()
|
||||
-- <- res1, res2
|
||||
ability SomeAbility:
|
||||
someStr: SomeStruct
|
||||
nested: NestedStruct
|
||||
al: SomeAlias
|
||||
someFunc(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> NestedStruct, SomeStruct, SomeAlias
|
||||
|
||||
service Srv("a"):
|
||||
check(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> NestedStruct
|
||||
check2() -> SomeStruct
|
||||
check3() -> SomeAlias
|
||||
|
||||
func withAb{SomeAbility}() -> SomeStruct:
|
||||
<- SomeAbility.someStr
|
||||
|
||||
func main(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> string:
|
||||
<- ""
|
@ -1,7 +1,15 @@
|
||||
module FooBars declares *
|
||||
aqua FooBars declares *
|
||||
|
||||
const DECLARE_CONST = "declare_const"
|
||||
const DECLARE_CONST2 = "declare_const2"
|
||||
|
||||
-- alias SomeStruct: string
|
||||
|
||||
data SomeStruct:
|
||||
a: string
|
||||
|
||||
-- service SomeStruct("ss"):
|
||||
-- a() -> string
|
||||
|
||||
func foo() -> string:
|
||||
<- "I am MyFooBar foo"
|
@ -85,7 +85,7 @@ class AquaLSPSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
println(
|
||||
c.variables
|
||||
.map(_.definition)
|
||||
.filter(v => v.name == fullName.getOrElse(checkName) && v.`type` == `type`)
|
||||
.filter(v => v.name == fullName.getOrElse(checkName))
|
||||
.map { case DefinitionInfo(name, token, t) =>
|
||||
val span = token.unit._1
|
||||
s"$name(${span.startIndex}:${span.endIndex}) $t"
|
||||
@ -348,4 +348,110 @@ class AquaLSPSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
ArrowType(NilType, ProductType(ScalarType.string :: Nil))
|
||||
) shouldBe true
|
||||
}
|
||||
|
||||
it should "resolve type tokens in one file correctly" in {
|
||||
val main =
|
||||
"""
|
||||
|aqua A declares withAb
|
||||
|
|
||||
|export main
|
||||
|
|
||||
|alias SomeAlias: string
|
||||
|
|
||||
|data NestedStruct:
|
||||
| a: SomeAlias
|
||||
|
|
||||
|data SomeStruct:
|
||||
| al: SomeAlias
|
||||
| nested: NestedStruct
|
||||
|
|
||||
|ability SomeAbility:
|
||||
| someStr: SomeStruct
|
||||
| nested: NestedStruct
|
||||
| al: SomeAlias
|
||||
| someFunc(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> NestedStruct, SomeStruct, SomeAlias
|
||||
|
|
||||
|service Srv("a"):
|
||||
| check(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> NestedStruct
|
||||
| check2() -> SomeStruct
|
||||
| check3() -> SomeAlias
|
||||
|
|
||||
|func withAb{SomeAbility}() -> SomeStruct:
|
||||
| Srv.check()
|
||||
| Srv.check2()
|
||||
| <- SomeAbility.someStr
|
||||
|
|
||||
|func main(ss: SomeStruct, nest: NestedStruct, al: SomeAlias) -> string:
|
||||
| Srv.check3()
|
||||
| <- ""
|
||||
|""".stripMargin
|
||||
|
||||
val src = Map(
|
||||
"index.aqua" -> main
|
||||
)
|
||||
|
||||
val res = compile(src, Map.empty).toOption.get.values.head
|
||||
|
||||
val nestedType = StructType("NestedStruct", NonEmptyMap.of(("a", ScalarType.string)))
|
||||
val someStr =
|
||||
StructType("SomeStruct", NonEmptyMap.of(("nested", nestedType), ("al", ScalarType.string)))
|
||||
|
||||
val abFuncType = ArrowType(
|
||||
ProductType.labelled(
|
||||
("ss", someStr) :: ("nest", nestedType) :: ("al", ScalarType.string) :: Nil
|
||||
),
|
||||
ProductType(nestedType :: someStr :: ScalarType.string :: Nil)
|
||||
)
|
||||
val someAb = AbilityType(
|
||||
"SomeAbility",
|
||||
NonEmptyMap.of(
|
||||
("someStr", someStr),
|
||||
("nested", nestedType),
|
||||
("al", ScalarType.string),
|
||||
("someFunc", abFuncType)
|
||||
)
|
||||
)
|
||||
|
||||
val srvType = ServiceType(
|
||||
"Srv",
|
||||
NonEmptyMap.of(
|
||||
(
|
||||
"check",
|
||||
ArrowType(
|
||||
ProductType.labelled(
|
||||
("ss", someStr) :: ("nest", nestedType) :: ("al", ScalarType.string) :: Nil
|
||||
),
|
||||
ProductType(nestedType :: Nil)
|
||||
)
|
||||
), ("check2", ArrowType(NilType, ProductType(someStr :: Nil))),
|
||||
("check3", ArrowType(NilType, ProductType(ScalarType.string :: Nil)))
|
||||
)
|
||||
)
|
||||
|
||||
res.checkTokenLoc(main, "SomeAlias", 0, ScalarType.string) shouldBe true
|
||||
Range.inclusive(1, 8).foreach { n =>
|
||||
res.checkLocations("SomeAlias", 0, n, main) shouldBe true
|
||||
}
|
||||
|
||||
res.checkTokenLoc(main, "NestedStruct", 0, nestedType) shouldBe true
|
||||
Range.inclusive(1, 7).foreach { n =>
|
||||
res.checkLocations("NestedStruct", 0, n, main) shouldBe true
|
||||
}
|
||||
|
||||
res.checkTokenLoc(main, "SomeStruct", 0, someStr) shouldBe true
|
||||
Range.inclusive(1, 7).foreach { n =>
|
||||
res.checkLocations("SomeStruct", 0, n, main) shouldBe true
|
||||
}
|
||||
|
||||
res.checkTokenLoc(main, "SomeAbility", 0, someAb) shouldBe true
|
||||
// from {SomeAbility} to 'ability SomeAbility'
|
||||
res.checkLocations("SomeAbility", 0, 1, main) shouldBe true
|
||||
// from 'SomeAbility.someStr' to {SomeAbility}
|
||||
res.checkLocations("SomeAbility", 1, 2, main) shouldBe true
|
||||
|
||||
res.checkTokenLoc(main, "Srv", 0, srvType) shouldBe true
|
||||
Range.inclusive(1, 3).foreach { n =>
|
||||
res.checkLocations("Srv", 0, n, main) shouldBe true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package aqua.parser.expr.func
|
||||
|
||||
import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, TypeToken, ValueToken}
|
||||
import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, NamedTypeToken, TypeToken, ValueToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.Span
|
||||
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}
|
||||
import aqua.parser.{ArrowReturnError, Ast, Expr, ParserError}
|
||||
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
import cats.~>
|
||||
@ -15,7 +14,6 @@ case class ArrowExpr[F[_]](arrowTypeExpr: ArrowTypeToken[F])
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): ArrowExpr[K] =
|
||||
copy(arrowTypeExpr.mapK(fk))
|
||||
|
||||
}
|
||||
|
||||
object ArrowExpr extends Expr.AndIndented {
|
||||
|
@ -110,7 +110,8 @@ object ScalarTypeToken {
|
||||
case class ArrowTypeToken[S[_]: Comonad](
|
||||
override val unit: S[Unit],
|
||||
args: List[(Option[Name[S]], TypeToken[S])],
|
||||
res: List[TypeToken[S]]
|
||||
res: List[TypeToken[S]],
|
||||
abilities: List[NamedTypeToken[S]] = Nil
|
||||
) extends TypeToken[S] {
|
||||
override def as[T](v: T): S[T] = unit.as(v)
|
||||
|
||||
@ -118,9 +119,11 @@ case class ArrowTypeToken[S[_]: Comonad](
|
||||
copy(
|
||||
fk(unit),
|
||||
args.map { case (n, t) => (n.map(_.mapK(fk)), t.mapK(fk)) },
|
||||
res.map(_.mapK(fk))
|
||||
)
|
||||
def argTypes: List[TypeToken[S]] = args.map(_._2)
|
||||
res.map(_.mapK(fk)),
|
||||
abilities.map(_.mapK(fk))
|
||||
)
|
||||
def argTypes: List[TypeToken[S]] = abilities ++ args.map(_._2)
|
||||
lazy val absWithArgs: List[(Option[Name[S]], TypeToken[S])] = abilities.map(n => Some(n.asName) -> n) ++ args
|
||||
}
|
||||
|
||||
object ArrowTypeToken {
|
||||
@ -133,8 +136,8 @@ object ArrowTypeToken {
|
||||
).map(_.toList)
|
||||
|
||||
// {SomeAb, SecondAb} for NamedTypeToken
|
||||
def abilities(): P0[List[(Option[Name[S]], NamedTypeToken[S])]] =
|
||||
(`{` *> comma(`Class`.surroundedBy(`/s*`).lift.map(s => Option(Name(s)) -> NamedTypeToken(s)))
|
||||
def abilities(): P0[List[NamedTypeToken[S]]] =
|
||||
(`{` *> comma(`Class`.surroundedBy(`/s*`).lift.map(NamedTypeToken(_)))
|
||||
.map(_.toList) <* `}`).?.map(_.getOrElse(List.empty))
|
||||
|
||||
def `arrowdef`(argTypeP: P[TypeToken[Span.S]]): P[ArrowTypeToken[Span.S]] =
|
||||
@ -144,8 +147,9 @@ object ArrowTypeToken {
|
||||
val args = argsList.map(Option.empty[Name[Span.S]] -> _)
|
||||
ArrowTypeToken(
|
||||
point,
|
||||
abs ++ args,
|
||||
res
|
||||
args,
|
||||
res,
|
||||
abs
|
||||
)
|
||||
}
|
||||
|
||||
@ -155,7 +159,7 @@ object ArrowTypeToken {
|
||||
.surroundedBy(`/s*`)
|
||||
) <* (`/s*` *> `)` <* ` `.?)) ~
|
||||
(` -> ` *> returnDef()).?).map { case (((abilities, point), args), res) =>
|
||||
ArrowTypeToken(point, abilities ++ args, res.toList.flatMap(_.toList))
|
||||
ArrowTypeToken(point, args, res.toList.flatMap(_.toList), abilities)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,15 +75,17 @@ object AquaSpec {
|
||||
|
||||
def toArrowType(
|
||||
args: List[BasicTypeToken[Id]],
|
||||
res: Option[BasicTypeToken[Id]]
|
||||
res: Option[BasicTypeToken[Id]],
|
||||
abilities: List[NamedTypeToken[Id]] = Nil
|
||||
): ArrowTypeToken[Id] =
|
||||
ArrowTypeToken[Id]((), args.map(None -> _), res.toList)
|
||||
ArrowTypeToken[Id]((), args.map(None -> _), res.toList, abilities)
|
||||
|
||||
def toNamedArrow(
|
||||
args: List[(String, TypeToken[Id])],
|
||||
res: List[BasicTypeToken[Id]]
|
||||
res: List[BasicTypeToken[Id]],
|
||||
abilities: List[NamedTypeToken[Id]] = Nil
|
||||
): ArrowTypeToken[Id] =
|
||||
ArrowTypeToken[Id]((), args.map(ab => Some(Name[Id](ab._1)) -> ab._2), res)
|
||||
ArrowTypeToken[Id]((), args.map(ab => Some(Name[Id](ab._1)) -> ab._2), res, abilities)
|
||||
|
||||
def toNamedArg(str: String, customType: String): Arg[Id] =
|
||||
Arg[Id](str, toNamedType(customType))
|
||||
|
@ -33,11 +33,11 @@ class ArrowTypeExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
"onIn",
|
||||
toNamedArrow(
|
||||
List(
|
||||
"SomeAb" -> toNamedType("SomeAb"),
|
||||
"a" -> toNamedType("Custom"),
|
||||
"b" -> toNamedType("Custom2")
|
||||
),
|
||||
Nil
|
||||
Nil,
|
||||
toNamedType("SomeAb") :: Nil
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -165,14 +165,11 @@ class TypeTokenSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
arrowWithNames("{SomeAb, SecondAb}(a: A) -> B") should be(
|
||||
ArrowTypeToken[Id](
|
||||
(),
|
||||
(Some(Name[Id]("SomeAb")) -> NamedTypeToken[Id]("SomeAb")) :: (Some(
|
||||
Name[Id](
|
||||
"SecondAb"
|
||||
)
|
||||
) -> NamedTypeToken[Id]("SecondAb")) :: (
|
||||
(
|
||||
Some(Name[Id]("a")) -> NamedTypeToken[Id]("A")
|
||||
) :: Nil,
|
||||
List(NamedTypeToken[Id]("B"))
|
||||
List(NamedTypeToken[Id]("B")),
|
||||
NamedTypeToken[Id]("SomeAb") :: NamedTypeToken[Id]("SecondAb") :: Nil
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -29,11 +29,15 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
|
||||
def before[Alg[_]: Monad](implicit
|
||||
T: TypesAlgebra[S, Alg],
|
||||
N: NamesAlgebra[S, Alg]
|
||||
N: NamesAlgebra[S, Alg],
|
||||
L: LocationsAlgebra[S, Alg]
|
||||
): Alg[ArrowType] = for {
|
||||
arrowType <- T.beginArrowScope(arrowTypeExpr)
|
||||
// add locations before ability will be defined as new variable definition
|
||||
_ <- L.pointLocations(arrowTypeExpr.abilities.map(n => n.value -> n))
|
||||
absAsArgs = arrowTypeExpr.abilities.map(_.asName)
|
||||
// Create local variables
|
||||
_ <- expr.arrowTypeExpr.args.flatMap { case (name, _) => name }
|
||||
_ <- arrowTypeExpr.absWithArgs.flatMap { case (name, _) => name }
|
||||
.zip(arrowType.domain.toList)
|
||||
.traverse {
|
||||
case (argName, t: ArrowType) =>
|
||||
@ -137,7 +141,8 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
T: TypesAlgebra[S, Alg],
|
||||
N: NamesAlgebra[S, Alg],
|
||||
A: AbilitiesAlgebra[S, Alg],
|
||||
M: ManglerAlgebra[Alg]
|
||||
M: ManglerAlgebra[Alg],
|
||||
L: LocationsAlgebra[S, Alg]
|
||||
): Prog[Alg, Raw] =
|
||||
Prog
|
||||
.around(
|
||||
|
@ -1,10 +1,8 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.parser.expr.func.CallArrowExpr
|
||||
import aqua.parser.lexer.{CallArrowToken, IntoArrow, IntoField, PropertyToken, VarToken}
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, FuncOp}
|
||||
import aqua.raw.value.CallArrowRaw
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
@ -12,12 +10,9 @@ import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.types.{ProductType, StreamType, Type}
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.comonad.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.traverse.*
|
||||
|
||||
class CallArrowSem[S[_]](val expr: CallArrowExpr[S]) extends AnyVal {
|
||||
|
@ -99,7 +99,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
|
||||
case None =>
|
||||
(for {
|
||||
t <- OptionT(
|
||||
T.getType(name.value)
|
||||
T.resolveType(name.asTypeToken, mustBeDefined = false)
|
||||
).collect { case st: ServiceType => st }
|
||||
// A hack to report name error, better to refactor
|
||||
.flatTapNone(N.read(name))
|
||||
@ -429,7 +429,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
|
||||
|
||||
lazy val nameTypeFromService = for {
|
||||
st <- OptionT(
|
||||
T.getType(ab.value)
|
||||
T.resolveType(ab, mustBeDefined = false)
|
||||
).collect { case st: ServiceType => st }
|
||||
rename <- OptionT(
|
||||
A.getServiceRename(ab)
|
||||
|
@ -4,15 +4,17 @@ import aqua.parser.lexer.{Name, NamedTypeToken, Token}
|
||||
import aqua.raw.RawContext
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.semantics.Levenshtein
|
||||
import aqua.semantics.rules.locations.{DefinitionInfo, LocationsAlgebra}
|
||||
import aqua.semantics.rules.locations.LocationsAlgebra
|
||||
import aqua.semantics.rules.mangler.ManglerAlgebra
|
||||
import aqua.semantics.rules.report.ReportAlgebra
|
||||
import aqua.semantics.rules.{abilities, StackInterpreter}
|
||||
import aqua.semantics.rules.{StackInterpreter, abilities}
|
||||
import aqua.types.ArrowType
|
||||
import cats.data.{NonEmptyMap, State}
|
||||
|
||||
import cats.data.*
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.option.*
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
@ -62,7 +64,9 @@ class AbilitiesInterpreter[S[_], X](using
|
||||
}
|
||||
|
||||
override def isDefinedAbility(name: NamedTypeToken[S]): State[X, Boolean] =
|
||||
getState.map(_.abilities.contains(name.value))
|
||||
OptionT(getState.map(_.abilities.get(name.value))).semiflatTap { _ =>
|
||||
locations.pointLocation(name.value, name)
|
||||
}.isDefined
|
||||
|
||||
override def getArrow(name: NamedTypeToken[S], arrow: Name[S]): SX[Option[ArrowType]] =
|
||||
getAbility(name.value).flatMap {
|
||||
|
@ -14,7 +14,7 @@ import cats.syntax.validated.*
|
||||
|
||||
final case class TypeResolution[S[_], +T](
|
||||
`type`: T,
|
||||
definitions: List[(Token[S], NamedTypeToken[S])]
|
||||
occurrences: List[(Token[S], String)]
|
||||
)
|
||||
|
||||
object TypeResolution {
|
||||
@ -59,10 +59,7 @@ object TypeResolution {
|
||||
case OptionTypeToken(_, dtt) =>
|
||||
resolveCollection(dtt, "Option", OptionType.apply)(state)
|
||||
case ntt: NamedTypeToken[S] =>
|
||||
val defs = state
|
||||
.getTypeDefinition(ntt.value)
|
||||
.toList
|
||||
.map(ntt -> _)
|
||||
val defs = (ntt -> ntt.value) :: Nil
|
||||
|
||||
state
|
||||
.getType(ntt.value)
|
||||
@ -84,7 +81,7 @@ object TypeResolution {
|
||||
)(state: TypesState[S]): Res[S, ArrowType] = {
|
||||
val res = arrowTypeToken.res
|
||||
.traverse(typeToken => resolveTypeToken(typeToken)(state).toEither)
|
||||
val args = arrowTypeToken.args.traverse { case (argName, typeToken) =>
|
||||
val args = arrowTypeToken.absWithArgs.traverse { case (argName, typeToken) =>
|
||||
resolveTypeToken(typeToken)(state)
|
||||
.map(argName.map(_.value) -> _)
|
||||
.toEither
|
||||
@ -104,7 +101,7 @@ object TypeResolution {
|
||||
ProductType.maybeLabelled(argsLabeledTypes),
|
||||
ProductType(resTypes)
|
||||
)
|
||||
val defs = (argsTokens ++ resTokens)
|
||||
val defs = argsTokens ++ resTokens
|
||||
|
||||
TypeResolution(typ, defs)
|
||||
}.toValidated
|
||||
|
@ -11,14 +11,12 @@ import cats.data.OptionT
|
||||
|
||||
trait TypesAlgebra[S[_], Alg[_]] {
|
||||
|
||||
def resolveType(token: TypeToken[S]): Alg[Option[Type]]
|
||||
def resolveType(token: TypeToken[S], mustBeDefined: Boolean = true): Alg[Option[Type]]
|
||||
|
||||
def resolveStreamType(token: TypeToken[S]): Alg[Option[StreamType]]
|
||||
|
||||
def resolveNamedType(token: TypeToken[S]): Alg[Option[AbilityType | StructType]]
|
||||
|
||||
def getType(name: String): Alg[Option[Type]]
|
||||
|
||||
def resolveArrowDef(arrowDef: ArrowTypeToken[S]): Alg[Option[ArrowType]]
|
||||
|
||||
def resolveServiceType(name: NamedTypeToken[S]): Alg[Option[ServiceType]]
|
||||
|
@ -11,6 +11,7 @@ import aqua.semantics.rules.types.TypeResolution.TypeResolutionError
|
||||
import aqua.types.*
|
||||
import aqua.types.Type.*
|
||||
|
||||
import cats.Applicative
|
||||
import cats.data.*
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.syntax.applicative.*
|
||||
@ -18,12 +19,11 @@ import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.monad.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Applicative, ~>}
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.reflect.TypeTest
|
||||
|
||||
@ -41,18 +41,16 @@ class TypesInterpreter[S[_], X](using
|
||||
|
||||
type ST[A] = State[X, A]
|
||||
|
||||
override def getType(name: String): State[X, Option[Type]] =
|
||||
getState.map(st => st.strict.get(name))
|
||||
|
||||
override def resolveType(token: TypeToken[S]): State[X, Option[Type]] =
|
||||
override def resolveType(token: TypeToken[S], mustBeDefined: Boolean = true): State[X, Option[Type]] =
|
||||
getState.map(TypeResolution.resolveTypeToken(token)).flatMap {
|
||||
case Valid(TypeResolution(typ, tokens)) =>
|
||||
val tokensLocs = tokens.map { case (t, n) => n.value -> t }
|
||||
val tokensLocs = tokens.map { case (t, n) => n -> t }
|
||||
locations.pointLocations(tokensLocs).as(typ.some)
|
||||
case Invalid(errors) =>
|
||||
case Invalid(errors) if mustBeDefined =>
|
||||
errors.traverse_ { case TypeResolutionError(token, hint) =>
|
||||
report.error(token, hint)
|
||||
}.as(none)
|
||||
case _ => none.pure
|
||||
}
|
||||
|
||||
override def resolveStreamType(token: TypeToken[S]): State[X, Option[StreamType]] =
|
||||
@ -70,7 +68,7 @@ class TypesInterpreter[S[_], X](using
|
||||
override def resolveArrowDef(arrowDef: ArrowTypeToken[S]): State[X, Option[ArrowType]] =
|
||||
getState.map(TypeResolution.resolveArrowDef(arrowDef)).flatMap {
|
||||
case Valid(TypeResolution(tt, tokens)) =>
|
||||
val tokensLocs = tokens.map { case (t, n) => n.value -> t }
|
||||
val tokensLocs = tokens.map { case (t, n) => n -> t }
|
||||
locations.pointLocations(tokensLocs).as(tt.some)
|
||||
case Invalid(errs) =>
|
||||
errs.traverse_ { case TypeResolutionError(token, hint) =>
|
||||
@ -155,7 +153,7 @@ class TypesInterpreter[S[_], X](using
|
||||
): State[X, Option[StructType]] =
|
||||
ensureNameNotDefined(name.value, name, ifDefined = none)(
|
||||
fields.toList.traverse {
|
||||
case (field, (fieldName, t: DataType)) =>
|
||||
case (field, (_, t: DataType)) =>
|
||||
(field -> t).some.pure[ST]
|
||||
case (field, (fieldName, t)) =>
|
||||
report
|
||||
@ -180,8 +178,7 @@ class TypesInterpreter[S[_], X](using
|
||||
)
|
||||
|
||||
override def defineAlias(name: NamedTypeToken[S], target: Type): State[X, Boolean] =
|
||||
getState.map(_.definitions.get(name.value)).flatMap {
|
||||
case Some(n) if n == name => State.pure(false)
|
||||
getState.map(_.getType(name.value)).flatMap {
|
||||
case Some(_) => report.error(name, s"Type `${name.value}` was already defined").as(false)
|
||||
case None =>
|
||||
modify(_.defineType(name, target))
|
||||
@ -269,7 +266,7 @@ class TypesInterpreter[S[_], X](using
|
||||
ensureTypeMatches(arg, expectedType, argType)
|
||||
}
|
||||
|
||||
locations.pointFieldLocation(abName, opName, op) *>
|
||||
locations.pointFieldLocation(ab.name, opName, op) *>
|
||||
reportNotEnoughArguments *>
|
||||
reportTooManyArguments *>
|
||||
checkArgumentTypes.map(typesMatch =>
|
||||
@ -367,6 +364,7 @@ class TypesInterpreter[S[_], X](using
|
||||
right: Type
|
||||
): State[X, Boolean] = {
|
||||
// TODO: This needs more comprehensive logic
|
||||
@tailrec
|
||||
def isComparable(lt: Type, rt: Type): Boolean =
|
||||
(lt, rt) match {
|
||||
// All numbers are comparable
|
||||
@ -485,7 +483,7 @@ class TypesInterpreter[S[_], X](using
|
||||
}
|
||||
expectedKeys = expected.fields.keys.toNonEmptyList
|
||||
/* Report unexpected arguments */
|
||||
_ <- arguments.toNel.traverse_ { case (name, arg -> typ) =>
|
||||
_ <- arguments.toNel.traverse_ { case (name, arg -> _) =>
|
||||
expected.fields.lookup(name) match {
|
||||
case Some(_) => State.pure(())
|
||||
case None =>
|
||||
@ -605,7 +603,7 @@ class TypesInterpreter[S[_], X](using
|
||||
report
|
||||
.error(
|
||||
token,
|
||||
s"Number of arguments doesn't match the function type, expected: ${expected}, given: $givenNum"
|
||||
s"Number of arguments doesn't match the function type, expected: $expected, given: $givenNum"
|
||||
)
|
||||
.as(false)
|
||||
|
||||
@ -613,7 +611,7 @@ class TypesInterpreter[S[_], X](using
|
||||
Applicative[ST]
|
||||
.product(
|
||||
// Collect argument types
|
||||
token.args
|
||||
token.absWithArgs
|
||||
.foldLeft(Chain.empty[(String, Type)].pure[ST]) {
|
||||
case (f, (Some(argName), argType)) =>
|
||||
f.flatMap(acc =>
|
||||
@ -720,7 +718,7 @@ class TypesInterpreter[S[_], X](using
|
||||
)(
|
||||
ifNotDefined: => State[X, A]
|
||||
): State[X, A] = getState
|
||||
.map(_.definitions.get(name))
|
||||
.map(_.getType(name))
|
||||
.flatMap {
|
||||
case Some(_) =>
|
||||
// TODO: Point to both locations here
|
||||
|
@ -2,38 +2,25 @@ package aqua.semantics.rules.types
|
||||
|
||||
import aqua.parser.lexer.*
|
||||
import aqua.raw.RawContext
|
||||
import aqua.raw.value.{FunctorRaw, IntoIndexRaw, LiteralRaw, PropertyRaw, ValueRaw}
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.types.*
|
||||
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{Chain, NonEmptyChain, ValidatedNec}
|
||||
import cats.kernel.Monoid
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.bifunctor.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.validated.*
|
||||
|
||||
case class TypesState[S[_]](
|
||||
fields: Map[String, (Name[S], Type)] = Map(),
|
||||
strict: Map[String, Type] = Map.empty,
|
||||
definitions: Map[String, NamedTypeToken[S]] = Map(),
|
||||
stack: List[TypesState.Frame[S]] = Nil
|
||||
) {
|
||||
def isDefined(t: String): Boolean = strict.contains(t)
|
||||
|
||||
def defineType(name: NamedTypeToken[S], `type`: Type): TypesState[S] =
|
||||
copy(
|
||||
strict = strict.updated(name.value, `type`),
|
||||
definitions = definitions.updated(name.value, name)
|
||||
strict = strict.updated(name.value, `type`)
|
||||
)
|
||||
|
||||
def getType(name: String): Option[Type] =
|
||||
strict.get(name)
|
||||
|
||||
def getTypeDefinition(name: String): Option[NamedTypeToken[S]] =
|
||||
definitions.get(name)
|
||||
}
|
||||
|
||||
object TypesState {
|
||||
@ -55,7 +42,6 @@ object TypesState {
|
||||
override def combine(x: TypesState[S], y: TypesState[S]): TypesState[S] =
|
||||
TypesState(
|
||||
strict = x.strict ++ y.strict,
|
||||
definitions = x.definitions ++ y.definitions
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class TypeResolutionSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
base <- baseTypes
|
||||
(token, expected) = base
|
||||
} inside(resolve(token, Map("Struct" -> structType))) {
|
||||
case Valid(TypeResolution(result, Nil)) =>
|
||||
case Valid(TypeResolution(result, _)) =>
|
||||
result shouldEqual expected
|
||||
}
|
||||
}
|
||||
@ -100,7 +100,7 @@ class TypeResolutionSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
(btoken, btype) = base
|
||||
(mod, typ) = modifier
|
||||
} inside(resolve(mod(btoken), Map("Struct" -> structType))) {
|
||||
case Valid(TypeResolution(result, Nil)) =>
|
||||
case Valid(TypeResolution(result, _)) =>
|
||||
result shouldEqual typ(btype)
|
||||
}
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user