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

feat(compiler)!: Prohibit mutating options [LNG-277] #960

Merged
merged 30 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2e309b6
Parse any nested type
InversionSpaces Nov 3, 2023
309e43c
Refactor type system
InversionSpaces Nov 3, 2023
36da269
Fix restriction
InversionSpaces Nov 7, 2023
ad54628
Refactor type resolution
InversionSpaces Nov 7, 2023
b8d3821
Return stream definition
InversionSpaces Nov 7, 2023
8c95a4a
Update examples
InversionSpaces Nov 7, 2023
5e1dd27
Refactor
InversionSpaces Nov 7, 2023
efa92c4
Refactor
InversionSpaces Nov 7, 2023
d0168db
Refactor integration tests
InversionSpaces Nov 7, 2023
d0c3b52
Export service
InversionSpaces Nov 7, 2023
a11eaa3
Add integration test
InversionSpaces Nov 7, 2023
e3d2c0a
Fix args provider
InversionSpaces Nov 7, 2023
f9cff53
Add parser unit tests
InversionSpaces Nov 8, 2023
fd7be05
Add type resolution unit tests
InversionSpaces Nov 8, 2023
20d00f1
Add more unit tests
InversionSpaces Nov 8, 2023
1022463
DataTypeToken -> CompositeTypeToken
InversionSpaces Nov 8, 2023
5dc1c4a
GeneralStreamType -> MutableStreamType
InversionSpaces Nov 8, 2023
e101ab6
Refactor
InversionSpaces Nov 8, 2023
3cc9c02
Merge branch 'main' into feat/immutable-options-LNG-277
InversionSpaces Nov 9, 2023
f22bba8
Refactor TypeResolution
InversionSpaces Nov 9, 2023
dda4a81
colType -> collectionType
InversionSpaces Nov 9, 2023
3fa9320
Refactor
InversionSpaces Nov 9, 2023
eb3d2e5
Fix PushToStreamSem
InversionSpaces Nov 9, 2023
ae65986
BasicTypeToken -> ScalarTypeToken
InversionSpaces Nov 9, 2023
9ad1fc4
CompositeTypeToken -> BasicTypeToken
InversionSpaces Nov 9, 2023
1b82ef4
Fix for nil
InversionSpaces Nov 9, 2023
6e1fce9
Make stream collectible
InversionSpaces Nov 10, 2023
c90f492
Refactor collectible type
InversionSpaces Nov 10, 2023
09d3248
Use internalError
InversionSpaces Nov 10, 2023
a65c023
Add unit tests
InversionSpaces Nov 10, 2023
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
22 changes: 15 additions & 7 deletions aqua-run/src/main/scala/aqua/run/CliFunc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package aqua.run
import aqua.parser.lexer.{CallArrowToken, CollectionToken, LiteralToken, VarToken}
import aqua.parser.lift.Span
import aqua.raw.value.{CollectionRaw, LiteralRaw, ValueRaw, VarRaw}
import aqua.types.{ArrayType, BottomType}
import aqua.types.*

import cats.data.{NonEmptyChain, NonEmptyList, Validated, ValidatedNec}
import cats.data.Validated.{invalid, invalidNec, validNec}
import cats.{~>, Id}
import cats.syntax.traverse.*
import cats.syntax.validated.*
import cats.syntax.either.*
import cats.data.{NonEmptyChain, NonEmptyList, Validated, ValidatedNec}
import cats.syntax.comonad.*
import cats.syntax.either.*
import cats.syntax.option.*
import cats.syntax.traverse.*
import cats.syntax.validated.*
import cats.{Id, ~>}

case class CliFunc(name: String, args: List[ValueRaw] = Nil)

Expand Down Expand Up @@ -52,7 +52,15 @@ object CliFunc {
.map(
NonEmptyList
.fromList(_)
.map(l => CollectionRaw(l, ArrayType(l.head.baseType)))
.map(l =>
CollectionRaw(
l,
ArrayType(
// FIXME: Type of Literal should always be a DataType
l.head.baseType.asInstanceOf[DataType]
)
)
)
.getOrElse(ValueRaw.Nil)
)
.toValidatedNec
Expand Down
6 changes: 2 additions & 4 deletions aqua-run/src/main/scala/aqua/run/TypeValidator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package aqua.run

import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
import aqua.types.*

import cats.data.Validated.{invalidNec, validNec}
import cats.data.{Validated, ValidatedNec}
import cats.effect.kernel.Async
Expand All @@ -10,14 +11,11 @@ import cats.syntax.flatMap.*
import cats.syntax.partialOrder.*
import cats.syntax.show.*
import cats.syntax.traverse.*

import scala.collection.immutable.SortedMap
import scala.concurrent.ExecutionContext

object TypeValidator {

import aqua.types.Type.typesPartialOrder

/**
* Compare and validate type from Aqua file and type generated from JSON.
* Also, the validation will succeed if the JSON type is missing an array or an optional field.
Expand Down Expand Up @@ -69,7 +67,7 @@ object TypeValidator {
case (l: OptionType, r) =>
// if we have ?[][]string and [][][]string it must throw an error
validateTypes(name, l.element, Some(r), Some((l, r)))
case (l: BoxType, r: BoxType) =>
case (l: CollectionType, r: CollectionType) =>
validateTypes(name, l.element, Some(r.element), fullOptionType.orElse(Some(l, r)))

case (l, r) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package aqua.definitions

import aqua.definitions.*
import aqua.res.FuncRes
import aqua.types.*
import aqua.definitions.*

import io.circe.*
import io.circe.parser.*
import io.circe.syntax.*

import scala.annotation.tailrec

// Represents the Aqua types
Expand All @@ -16,7 +16,7 @@ sealed trait TypeDefinition {

object TypeDefinition {

implicit val encodeProdDefType: Encoder[ProductTypeDef] = {
given Encoder[ProductTypeDef] = {
case d @ LabeledProductTypeDef(fields) =>
Json.obj(
("tag", Json.fromString(d.tag)),
Expand All @@ -33,7 +33,7 @@ object TypeDefinition {
)
}

implicit val encodeDefType: Encoder[TypeDefinition] = {
given Encoder[TypeDefinition] = {
case d @ ScalarTypeDef(name) =>
Json.obj(
("tag", Json.fromString(d.tag)),
Expand Down Expand Up @@ -68,14 +68,14 @@ object TypeDefinition {
)
}

implicit val encodeServiceDefType: Encoder[ServiceDef] = { case ServiceDef(sId, functions, name) =>
given Encoder[ServiceDef] = { case ServiceDef(sId, functions, name) =>
Json.obj(
("defaultServiceId", sId.asJson),
("functions", encodeProdDefType(functions))
("functions", (functions: ProductTypeDef).asJson)
)
}

implicit val encodeNamesConfig: Encoder[NamesConfig] = { case n: NamesConfig =>
given Encoder[NamesConfig] = { case n: NamesConfig =>
import n.*
Json.obj(
("relay", Json.fromString(relay)),
Expand All @@ -88,13 +88,12 @@ object TypeDefinition {
)
}

implicit val encodeFunctionDefType: Encoder[FunctionDef] = {
case FunctionDef(fName, arrow, names) =>
Json.obj(
("functionName", Json.fromString(fName)),
("arrow", encodeDefType(arrow)),
("names", names.asJson)
)
given Encoder[FunctionDef] = { case FunctionDef(fName, arrow, names) =>
Json.obj(
("functionName", Json.fromString(fName)),
("arrow", (arrow: TypeDefinition).asJson),
("names", names.asJson)
)
}

def apply(t: Option[Type]): TypeDefinition = t.map(apply).getOrElse(NilTypeDef)
Expand All @@ -103,7 +102,7 @@ object TypeDefinition {
t match {
case OptionType(t) =>
OptionTypeDef(TypeDefinition(t))
case t: BoxType => ArrayTypeDef(TypeDefinition(t.element))
case t: CollectionType => ArrayTypeDef(TypeDefinition(t.element))
case StructType(name, fields) =>
StructTypeDef(name, fields.toSortedMap.view.mapValues(TypeDefinition.apply).toMap)
case AbilityType(name, fieldAndArrows) =>
Expand Down Expand Up @@ -198,7 +197,11 @@ case class NamesConfig(
)

// Describes service
case class ServiceDef(defaultServiceId: Option[String], functions: LabeledProductTypeDef, name: String)
case class ServiceDef(
defaultServiceId: Option[String],
functions: LabeledProductTypeDef,
name: String
)

// Describes top-level function
case class FunctionDef(
Expand Down
5 changes: 3 additions & 2 deletions backend/ts/src/main/scala/aqua/backend/OutputFunc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package aqua.backend
import aqua.backend.air.FuncAirGen
import aqua.backend.ts.TypeScriptCommon.fixupArgName
import aqua.backend.ts.{TSFuncTypes, TypeScriptCommon}
import aqua.definitions.*
import aqua.definitions.TypeDefinition.given
import aqua.res.FuncRes
import aqua.types.*

import cats.syntax.show.*
import io.circe.*
import io.circe.parser.*
Expand All @@ -20,8 +23,6 @@ case class OutputFunc(func: FuncRes, types: Types) {
val funcTypes = types.funcType(func)

import funcTypes.*
import aqua.definitions.TypeDefinition.*
import aqua.definitions.*

def generate: (AirFunction, String) = {
val tsAir = FuncAirGen(func).generate
Expand Down
5 changes: 3 additions & 2 deletions backend/ts/src/main/scala/aqua/backend/OutputService.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package aqua.backend

import aqua.backend.ts.TypeScriptCommon
import aqua.definitions.*
import aqua.definitions.TypeDefinition.given
import aqua.res.ServiceRes
import aqua.types.ArrowType

import io.circe.*
import io.circe.parser.*
import io.circe.syntax.*
Expand All @@ -14,8 +17,6 @@ case class OutputService(srv: ServiceRes, types: Types) {
private val serviceTypes = types.serviceType(srv)

import serviceTypes.*
import aqua.definitions.TypeDefinition.*
import aqua.definitions.*

def generate: String =
val functions = LabeledProductTypeDef(
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/aqua/examples/errorClear.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ service FailService("fail-srv"):

func errorClearTest(node: string, relay: string) -> string, i64:
stream: *string
code: ?i64
code: *i64

on node via relay:
try:
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/aqua/examples/funcs.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func ifCalc() -> u64:
<- res!0

func cmp(a: i32, b: i32, pred: i8 -> bool) -> bool:
result: ?bool
result: *bool

if a < b:
result <- pred(-1)
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/aqua/examples/handleResultError.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export handleResultError

-- t = true, f = false
func handleResultError(t: bool, f: bool) -> string:
opt: ?[]string
opt: *[]string

if t == f: -- false
opt <<- ["unreachable"]
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/aqua/examples/options/option_gen.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ service OptionString("opt_str"):
checkOption(str: ?string) -> string

func emptyString() -> ?string:
valueEmpty: ?string
valueEmpty: *string
<- valueEmpty

func checkEmpty() -> string:
Expand All @@ -11,7 +11,7 @@ func checkEmpty() -> string:
<- res

func stringAsOption(str: string) -> ?string:
valueEmpty: ?string
valueEmpty: *string
valueEmpty <<- str
<- valueEmpty

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/aqua/examples/stream.aqua
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func returnNilLength() -> u32:
<- arr.length

func stringNone() -> ?string:
valueNone: ?string
valueNone: *string
<- valueNone

func returnNone() -> ?string:
Expand Down
10 changes: 9 additions & 1 deletion integration-tests/aqua/examples/streamArgs.aqua
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
aqua StreamArgs

export retrieve_records, modify_stream, TestService

service TestService("test-service"):
get_records(key: string) -> []string

Expand All @@ -7,4 +11,8 @@ func append_records(peer: string, srum: *[]string):
func retrieve_records(peer: string) -> [][]string:
records: *[]string
append_records(peer, records)
<- records
<- records

func modify_stream(stream: *string) -> []string:
stream <<- "appended value"
<- stream
7 changes: 5 additions & 2 deletions integration-tests/aqua/examples/via.aqua
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
aqua Via

export viaArr, viaStream, viaOpt

import "@fluencelabs/aqua-lib/builtin.aqua"

func viaArr(node_id: string, viaAr: []string) -> Info:
on node_id via viaAr:
p <- Peer.identify()
<- p


func viaStream(node_id: string, viaStr: *string) -> Info:
on node_id via viaStr:
p <- Peer.identify()
<- p

func viaOpt(relay: string, node_id: string, viaOpt: ?string) -> Info:
func viaOpt(node_id: string, viaOpt: ?string) -> Info:
on node_id via viaOpt:
p <- Peer.identify()
<- p
35 changes: 29 additions & 6 deletions integration-tests/src/__test__/examples.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ import {
import {
abilityCall,
complexAbilityCall,
checkAbCallsCall, bugLNG258Call1, bugLNG258Call2, bugLNG258Call3, multipleAbilityWithClosureCall,
checkAbCallsCall,
bugLNG258Call1,
bugLNG258Call2,
bugLNG258Call3,
multipleAbilityWithClosureCall,
} from "../examples/abilityCall.js";
import {
nilLengthCall,
Expand Down Expand Up @@ -78,7 +82,10 @@ import { tryCatchCall } from "../examples/tryCatchCall.js";
import { tryOtherwiseCall } from "../examples/tryOtherwiseCall.js";
import { coCall } from "../examples/coCall.js";
import { bugLNG60Call, passArgsCall } from "../examples/passArgsCall.js";
import { streamArgsCall } from "../examples/streamArgsCall.js";
import {
streamArgsCall,
modifyStreamCall,
} from "../examples/streamArgsCall.js";
import { streamResultsCall } from "../examples/streamResultsCall.js";
import { structuralTypingCall } from "../examples/structuralTypingCall";
import {
Expand All @@ -104,7 +111,10 @@ import { multiReturnCall } from "../examples/multiReturnCall.js";
import { declareCall } from "../examples/declareCall.js";
import { genOptions, genOptionsEmptyString } from "../examples/optionsCall.js";
import { lng193BugCall } from "../examples/closureReturnRename.js";
import {closuresCall, multipleClosuresLNG262BugCall} from "../examples/closures.js";
import {
closuresCall,
multipleClosuresLNG262BugCall,
} from "../examples/closures.js";
import { closureArrowCaptureCall } from "../examples/closureArrowCapture.js";
import {
bugLNG63_2Call,
Expand Down Expand Up @@ -589,6 +599,18 @@ describe("Testing examples", () => {
expect(streamArgsResult).toEqual([["peer_id", "peer_id"]]);
});

it("streamArgs.aqua modify stream", async () => {
let streamArgsResult = await modifyStreamCall([
"passed value 1",
"passed value 2",
]);
expect(streamArgsResult).toEqual([
"passed value 1",
"passed value 2",
"appended value",
]);
});

it("streamResults.aqua", async () => {
let streamResultsResult = await streamResultsCall();
expect(streamResultsResult).toEqual(["new_name", "new_name", "new_name"]);
Expand Down Expand Up @@ -934,9 +956,10 @@ describe("Testing examples", () => {

it("via.aqua", async () => {
let res1 = await viaArrCall();
let res2 = await viaOptCall(relayPeerId1);
let res3 = await viaOptNullCall(relayPeerId1);
let res4 = await viaStreamCall(relayPeerId1);
let res2 = await viaOptCall();
let res3 = await viaOptNullCall();
let res4 = await viaStreamCall();
expect(res1).not.toHaveLength(0);
expect(res1).toEqual(res2);
expect(res2).toEqual(res3);
expect(res3).toEqual(res4);
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/src/examples/streamArgsCall.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
retrieve_records,
modify_stream,
registerTestService,
} from "../compiled/examples/streamArgs.js";

Expand All @@ -12,3 +13,7 @@ export async function streamArgsCall() {

return await retrieve_records("peer_id");
}

export async function modifyStreamCall(arg: string[]) {
return await modify_stream(arg);
}
Loading
Loading