Skip to content

Commit

Permalink
fix(compiler): Type check arrow calls on services and abilities [LNG-315
Browse files Browse the repository at this point in the history
] (#1037)

* Rewrite resolveIntoArrow

* Refactor

* Refactor resolveIntoCopy

* Refactor resolveIntoIndex

* Refactor resolveIntoField

* Fix test

* Remove package-lock.json

* Add tests

* Add comment
  • Loading branch information
InversionSpaces authored Jan 10, 2024
1 parent 5241f52 commit d46ee03
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 119 deletions.
2 changes: 1 addition & 1 deletion integration-tests/aqua/examples/abilitiesClosure.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ability WorkerJob:

func disjoint_run{WorkerJob}() -> -> string:
run = func () -> string:
r <- WorkerJob.runOnSingleWorker()
r <- WorkerJob.runOnSingleWorker("worker")
<- r
<- run

Expand Down
41 changes: 25 additions & 16 deletions semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,38 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
private def resolveSingleProperty(rootType: Type, op: PropertyOp[S]): Alg[Option[PropertyRaw]] =
op match {
case op: IntoField[S] =>
T.resolveField(rootType, op)
case op: IntoArrow[S] =>
for {
maybeArgs <- op.arguments.traverse(valueToRaw)
arrowProp <- maybeArgs.sequence.flatTraverse(
T.resolveArrow(rootType, op, _)
OptionT(T.resolveIntoField(op, rootType))
.map(
_.fold(
field = t => IntoFieldRaw(op.value, t),
property = t => FunctorRaw(op.value, t)
)
)
} yield arrowProp
.value
case op: IntoArrow[S] =>
(for {
args <- op.arguments.traverse(arg => OptionT(valueToRaw(arg)))
argTypes = args.map(_.`type`)
arrowType <- OptionT(T.resolveIntoArrow(op, rootType, argTypes))
} yield IntoArrowRaw(op.name.value, arrowType, args)).value
case op: IntoCopy[S] =>
(for {
_ <- OptionT.liftF(
reportNamedArgsDuplicates(op.args)
)
fields <- op.args.traverse(arg => OptionT(valueToRaw(arg.argValue)).map(arg -> _))
prop <- OptionT(T.resolveCopy(op, rootType, fields))
} yield prop).value
case op: IntoIndex[S] =>
for {
maybeIdx <- op.idx.fold(LiteralRaw.Zero.some.pure)(valueToRaw)
idxProp <- maybeIdx.flatTraverse(
T.resolveIndex(rootType, op, _)
args <- op.args.traverse(arg =>
OptionT(valueToRaw(arg.argValue)).map(
arg.argName.value -> _
)
)
} yield idxProp
argsTypes = args.map { case (_, raw) => raw.`type` }
structType <- OptionT(T.resolveIntoCopy(op, rootType, argsTypes))
} yield IntoCopyRaw(structType, args.toNem)).value
case op: IntoIndex[S] =>
(for {
idx <- OptionT(op.idx.fold(LiteralRaw.Zero.some.pure)(valueToRaw))
valueType <- OptionT(T.resolveIntoIndex(op, rootType, idx.`type`))
} yield IntoIndexRaw(idx, valueType)).value
}

def valueToRaw(v: ValueToken[S]): Alg[Option[ValueRaw]] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,74 @@ trait TypesAlgebra[S[_], Alg[_]] {

def defineAlias(name: NamedTypeToken[S], target: Type): Alg[Boolean]

def resolveIndex(rootT: Type, op: IntoIndex[S], idx: ValueRaw): Alg[Option[PropertyRaw]]
/**
* Resolve `IntoIndex` property on value with `rootT` type
*
* @param op property to resolve
* @param rootT type of the value to which property is applied
* @param idxType type of the index
* @return type of the value at given index if property application is valid
*/
def resolveIntoIndex(
op: IntoIndex[S],
rootT: Type,
idxType: Type
): Alg[Option[DataType]]

def resolveCopy(
token: IntoCopy[S],
/**
* Resolve `IntoCopy` property on value with `rootT` type
*
* @param op property to resolve
* @param rootT type of the value to which property is applied
* @param types types of arguments passed
* @return struct type if property application is valid
* @note `types` should correspond to `op.args`
*/
def resolveIntoCopy(
op: IntoCopy[S],
rootT: Type,
fields: NonEmptyList[(NamedArg[S], ValueRaw)]
): Alg[Option[PropertyRaw]]
types: NonEmptyList[Type]
): Alg[Option[StructType]]

def resolveField(rootT: Type, op: IntoField[S]): Alg[Option[PropertyRaw]]
enum IntoFieldRes(`type`: Type) {
case Field(`type`: Type) extends IntoFieldRes(`type`)
case Property(`type`: Type) extends IntoFieldRes(`type`)

def resolveArrow(
rootT: Type,
def fold[A](field: Type => A, property: Type => A): A =
this match {
case Field(t) => field(t)
case Property(t) => property(t)
}
}

/**
* Resolve `IntoField` property on value with `rootT` type
*
* @param op property to resolve
* @param rootT type of the value to which property is applied
* @return if property application is valid, return
* Field(type) if it's a field of rootT (fields of structs or abilities),
* Property(type) if it's a property of rootT (functors of collections)
*/
def resolveIntoField(
op: IntoField[S],
rootT: Type
): Alg[Option[IntoFieldRes]]

/**
* Resolve `IntoArrow` property on value with `rootT` type
*
* @param op property to resolve
* @param rootT type of the value to which property is applied
* @param types types of arguments passed
* @return arrow type if property application is valid
* @note `types` should correspond to `op.arguments`
*/
def resolveIntoArrow(
op: IntoArrow[S],
arguments: List[ValueRaw]
): Alg[Option[PropertyRaw]]
rootT: Type,
types: List[Type]
): Alg[Option[ArrowType]]

def ensureValuesComparable(token: Token[S], left: Type, right: Type): Alg[Boolean]

Expand Down
Loading

0 comments on commit d46ee03

Please sign in to comment.