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): Return ability arrow [LNG-258] #935

Merged
merged 10 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 14 additions & 21 deletions aqua-src/antithesis.aqua
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
aqua M
aqua A

export getObj
export test

service OpNum("op"):
identity(n: u32) -> u32
ability InnerAb:
arrow() -> i8, i8

service OpStr("op"):
identity(n: string) -> string
ability TestAb:
inner: InnerAb

service OpArr("op"):
identity(arr: []string) -> []string
func create() -> TestAb:
arrow = () -> i8, i8:
<- 42, 76
<- TestAb(inner = InnerAb(arrow = arrow))

data InnerObj:
arr: []string
num: u32

data SomeObj:
str: string
num: u64
inner: InnerObj

func getObj() -> SomeObj:
b = SomeObj(str = OpStr.identity("some str"), num = 5, inner = InnerObj(arr = ["a", "b", "c"], num = 6))
c = b.copy(str = "new str", inner = b.inner.copy(num = 3))
<- c
func test() -> i8, i8:
ababab <- create()
res1, res2 <- ababab.inner.arrow()
<- res1, res2
6 changes: 4 additions & 2 deletions integration-tests/aqua/examples/abilities.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,13 @@ ability CCCC:
arrow(x: i8) -> bool
simple: SSS

func checkAbCalls() -> bool, bool:
func checkAbCalls() -> bool, bool, bool:
closure = (x: i8) -> bool:
<- x > 20

MySSS = SSS(arrow = closure)
MyCCCC = CCCC(simple = MySSS, arrow = MySSS.arrow)
res1 <- MySSS.arrow(42)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this test the bug fix?
Let's create a separate test with:

  • Abilities returned from func
  • Abilities with names ab, Ab, AB (or similar in terms of case)

res2 = MyCCCC.arrow(12)

<- MySSS.arrow(42), MyCCCC.arrow(12)
<- res1, res2, MySSS.arrow(50)
2 changes: 1 addition & 1 deletion integration-tests/src/__test__/examples.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ describe("Testing examples", () => {

it("ability.aqua ability calls", async () => {
let result = await checkAbCallsCall();
expect(result).toStrictEqual([true, false]);
expect(result).toStrictEqual([true, false, true]);
});

it("functors.aqua LNG-119 bug", async () => {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/src/examples/abilityCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ export async function complexAbilityCall(): Promise<[boolean, boolean]> {
return await bug214();
}

export async function checkAbCallsCall(): Promise<[boolean, boolean]> {
export async function checkAbCallsCall(): Promise<[boolean, boolean, boolean]> {
return await checkAbCalls();
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
abilityType: NamedType,
p: PropertyRaw
): State[S, (VarModel, Inline)] = p match {
case IntoArrowRaw(arrowName, t, arguments) =>
case IntoArrowRaw(arrowName, _, arguments) =>
val arrowType = abilityType.fields
.lookup(arrowName)
.collect { case at @ ArrowType(_, _) =>
Expand Down Expand Up @@ -82,9 +82,9 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
}
}
} yield result
case IntoFieldRaw(fieldName, at @ AbilityType(abName, fields)) =>
case IntoFieldRaw(fieldName, at @ AbilityType(_, _)) =>
(VarModel(AbilityType.fullName(varModel.name, fieldName), at), Inline.empty).pure
case IntoFieldRaw(fieldName, t) =>
case IntoFieldRaw(fieldName, _) =>
for {
abilityField <- Exports[S].getAbilityField(varModel.name, fieldName)
result <- abilityField match {
Expand All @@ -102,6 +102,18 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi

}
} yield result
case icr: IntoCopyRaw =>
internalError(
s"Inlining, cannot use 'copy' ($icr) in ability ($varModel)"
)
case fr: FunctorRaw =>
internalError(
s"Inlining, cannot use functor ($fr) in ability ($varModel)"
)
case iir: IntoIndexRaw =>
internalError(
s"Inlining, cannot use index ($iir) in ability ($varModel)"
)
}

private[inline] def unfoldProperty[S: Mangler: Exports: Arrows](
Expand Down Expand Up @@ -154,6 +166,10 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
mergeMode = SeqMode
)
}
case iar: IntoArrowRaw =>
internalError(
s"Inlining, cannot use arrow ($iar) in non-ability type ($varModel)"
)
}

// Helper for `optimizeProperties`
Expand Down Expand Up @@ -211,7 +227,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
State.pure((vm, prevInline.mergeWith(optimizationInline, SeqMode)))
) { case (state, property) =>
state.flatMap {
case (vm @ Ability(name, at, _), leftInline) =>
case (vm @ Ability(_, at, _), leftInline) =>
unfoldAbilityProperty(vm, at, property.raw).map { case (vm, inl) =>
(
vm,
Expand Down Expand Up @@ -317,8 +333,8 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
raw: ValueRaw,
properties: Chain[PropertyRaw],
propertiesAllowed: Boolean
): State[S, (ValueModel, Inline)] = {
((raw, properties.uncons) match {
): State[S, (ValueModel, Inline)] =
(raw, properties.uncons) match {
/**
* To inline
*/
Expand All @@ -338,7 +354,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
propertiesAllowed
)
} yield propsInlined
case l =>
case _ =>
internalError(
s"Unfolded stream ($vr) cannot be a literal"
)
Expand All @@ -362,9 +378,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
}
}
}
})

}
}

/**
* Remove properties from the var and return a new var without them
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package aqua.model.inline.raw

import aqua.errors.Errors.internalError
import aqua.model.*
import aqua.model.inline.RawValueInliner.{callToModel, valueToModel}
import aqua.model.inline.RawValueInliner.callToModel
import aqua.model.inline.state.{Arrows, Exports, Mangler}
import aqua.model.inline.{ArrowInliner, Inline, TagInliner}
import aqua.model.inline.{ArrowInliner, Inline, RawValueInliner}
import aqua.raw.ops.Call
import aqua.raw.value.CallArrowRaw
import aqua.types.AbilityType
DieMyst marked this conversation as resolved.
Show resolved Hide resolved

import cats.data.{Chain, State}
import cats.syntax.traverse.*
Expand All @@ -17,7 +18,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
private[inline] def unfold[S: Mangler: Exports: Arrows](
value: CallArrowRaw,
exportTo: List[Call.Export]
): State[S, (List[ValueModel], Inline)] = Exports[S].exports.flatMap { exports =>
): State[S, (List[ValueModel], Inline)] = {
logger.trace(s"${exportTo.mkString(" ")} $value")

val call = Call(value.arguments, exportTo)
Expand All @@ -28,7 +29,16 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
val funcName = value.ability.fold(value.name)(_ + "." + value.name)
logger.trace(s" $funcName")

resolveArrow(funcName, call)
value.abValue.map { v =>
// inline var to get the left side of the ability call's name
RawValueInliner.unfold(v, false).flatMap {
DieMyst marked this conversation as resolved.
Show resolved Hide resolved
case (VarModel(name, _, _), _) =>
resolveArrow(AbilityType.fullName(name, funcName), call)
InversionSpaces marked this conversation as resolved.
Show resolved Hide resolved
case l =>
internalError(s"Ability cannot be a literal ($l)")
}
}.getOrElse(resolveArrow(funcName, call))

}

private def resolveFuncArrow[S: Mangler: Exports: Arrows](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@ import aqua.model.ValueModel.Ability
import cats.Eval
import cats.data.{Chain, IndexedStateT, NonEmptyMap, State}
import cats.syntax.foldable.*
import cats.syntax.functor.*

object MakeAbilityRawInliner extends RawInliner[AbilityRaw] {

private def updateFields[S: Mangler: Exports: Arrows](
name: String,
fields: NonEmptyMap[String, (ValueModel, Inline)]
): State[S, Unit] = {
for {
res <- fields.toNel.traverse {
case (n, (Ability(abilityName, _, _), _)) =>
val leftName = AbilityType.fullName(name, n)
Exports[S].copyWithAbilityPrefix(abilityName, leftName)
case (n, (vm, _)) =>
Exports[S].resolveAbilityField(name, n, vm)
}
} yield ()
}
): State[S, Unit] =
fields.toNel.traverse {
case (n, (Ability(abilityName, _, _), _)) =>
val leftName = AbilityType.fullName(name, n)
Exports[S].copyWithAbilityPrefix(abilityName, leftName)
case (n, (vm, _)) =>
Exports[S].resolveAbilityField(name, n, vm)
}.as(())

override def apply[S: Mangler: Exports: Arrows](
raw: AbilityRaw,
Expand Down
6 changes: 3 additions & 3 deletions model/raw/src/main/scala/aqua/raw/value/PropertyRaw.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package aqua.raw.value

import aqua.types.{StructType, Type}
import aqua.types.{ArrowType, NilType, StructType, Type}
import cats.data.NonEmptyMap

sealed trait PropertyRaw {
Expand All @@ -22,10 +22,10 @@ case class IntoFieldRaw(name: String, `type`: Type) extends PropertyRaw {
override def varNames: Set[String] = Set.empty
}

case class IntoArrowRaw(name: String, arrowType: Type, arguments: List[ValueRaw])
case class IntoArrowRaw(name: String, arrowType: ArrowType, arguments: List[ValueRaw])
extends PropertyRaw {

override def `type`: Type = arrowType
override def `type`: Type = arrowType.codomain.uncons.map(_._1).getOrElse(NilType)

override def map(f: ValueRaw => ValueRaw): PropertyRaw =
copy(arguments = arguments.map(f))
Expand Down
4 changes: 3 additions & 1 deletion model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,9 @@ case class CallArrowRaw(
ability: Option[String],
name: String,
arguments: List[ValueRaw],
baseType: ArrowType
baseType: ArrowType,
InversionSpaces marked this conversation as resolved.
Show resolved Hide resolved
// left part of an ability (what calls arrow)
abValue: Option[ValueRaw] = None
InversionSpaces marked this conversation as resolved.
Show resolved Hide resolved
) extends ValueRaw {
override def `type`: Type = baseType.codomain.headOption.getOrElse(baseType)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import aqua.semantics.Prog
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import aqua.types.{StreamType, Type}

import aqua.types.{ProductType, StreamType, Type}
import cats.Monad
import cats.syntax.flatMap.*
import cats.syntax.functor.*
Expand All @@ -24,11 +23,11 @@ class CallArrowSem[S[_]](val expr: CallArrowExpr[S]) extends AnyVal {

import expr.*

private def getExports[Alg[_]: Monad](callArrow: CallArrowRaw)(using
private def getExports[Alg[_]: Monad](codomain: ProductType)(using
N: NamesAlgebra[S, Alg],
T: TypesAlgebra[S, Alg]
): Alg[List[Call.Export]] =
(variables zip callArrow.baseType.codomain.toList).traverse { case (v, t) =>
(variables zip codomain.toList).traverse { case (v, t) =>
N.read(v, mustBeDefined = false).flatMap {
case Some(stream @ StreamType(st)) =>
T.ensureTypeMatches(v, st, t).as(Call.Export(v.value, stream))
Expand All @@ -45,7 +44,7 @@ class CallArrowSem[S[_]](val expr: CallArrowExpr[S]) extends AnyVal {
// TODO: Accept other expressions
callArrowRaw <- V.valueToCallArrowRaw(expr.callArrow)
tag <- callArrowRaw.traverse(car =>
getExports(car).map(CallArrowRawTag(_, car)) <*
getExports(car.baseType.codomain).map(CallArrowRawTag(_, car)) <*
T.checkArrowCallResults(callArrow, car.baseType, variables)
)
} yield tag.map(_.funcOpLeaf)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
valueToRaw(v).flatMap(
_.flatTraverse {
case ca: CallArrowRaw => ca.some.pure[Alg]
case ApplyPropertyRaw(value, IntoArrowRaw(name, arrowType, arguments)) =>
InversionSpaces marked this conversation as resolved.
Show resolved Hide resolved
// IntoArrow can be only last in a properties chain
// Store left part of the value and properties into CallArrowRaw to inline it later
CallArrowRaw(None, name, arguments, arrowType, Some(value)).some.pure[Alg]
// TODO: better error message (`raw` formatting)
case raw => report.error(v, s"Expected arrow call, got $raw").as(none)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,18 @@ class TypesInterpreter[S[_], X](using
s"Arrow `${op.name.value}` not found in type `$name`, available: ${fieldsAndArrows.toNel.toList.map(_._1).mkString(", ")}"
)
.as(None)
) { t =>
val resolvedType = t match {
// TODO: is it a correct way to resolve `IntoArrow` type?
case ArrowType(_, codomain) => codomain.uncons.map(_._1).getOrElse(t)
case _ => t
}
locations
.pointFieldLocation(name, op.name.value, op)
.as(Some(IntoArrowRaw(op.name.value, resolvedType, arguments)))
) {
case at@ArrowType(_, _) =>
locations
.pointFieldLocation(name, op.name.value, op)
.as(Some(IntoArrowRaw(op.name.value, at, arguments)))
case _ =>
report
.error(
op,
s"Unexpected. `${op.name.value}` must be an arrow."
)
.as(None)
}
case t =>
t.properties
Expand Down
Loading