Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler): Type check arrow calls on services and abilities [LNG-315] #1037

Merged
merged 11 commits into from
Jan 10, 2024
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
Loading