diff --git a/aqua-src/antithesis.aqua b/aqua-src/antithesis.aqua index f475f626..ff45751f 100644 --- a/aqua-src/antithesis.aqua +++ b/aqua-src/antithesis.aqua @@ -1,15 +1,10 @@ -service Console("run-console"): - print(any: ⊤) - get() -> string - zzz() -> string - -data Azazaz: - s: string - -func exec(peers: []string) -> []string: - on "": - closure = (s: Azazaz) -> Azazaz: - Console.get() +func returnCall() -> string -> string: + closure = (s: string) -> string: <- s - Console.zzz() - <- peers + closure("123asdf") + <- closure + +func test() -> string: + a = returnCall() + b = a("arg") + <- b \ No newline at end of file diff --git a/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala b/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala index a297c31b..d7af9c33 100644 --- a/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala @@ -3,6 +3,7 @@ package aqua.model.inline import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler} import aqua.model.* import aqua.raw.ops.RawTag +import aqua.types.ArrowType import aqua.raw.value.{ValueRaw, VarRaw} import aqua.types.{BoxType, StreamType} import cats.data.{Chain, State, StateT} @@ -131,14 +132,24 @@ object ArrowInliner extends Logging { argsToArrows = argsToArrowsRaw.map { case (k, v) => argsShouldRename.getOrElse(k, k) -> v } + returnedArrows = fn.ret.collect { case VarRaw(name, ArrowType(_, _)) => + name + }.toSet + + returnedArrowsShouldRename <- Mangler[S].findNewNames(returnedArrows) + renamedCapturedArrows = fn.capturedArrows.map { case (k, v) => + returnedArrowsShouldRename.getOrElse(k, k) -> v + } + // Going to resolve arrows: collect them all. Names should never collide: it's semantically checked _ <- Arrows[S].purge - _ <- Arrows[S].resolved(fn.capturedArrows ++ argsToArrows) + _ <- Arrows[S].resolved(renamedCapturedArrows ++ argsToArrows) // Rename all renamed arguments in the body treeRenamed = fn.body .rename(argsShouldRename) + .rename(returnedArrowsShouldRename) .map(_.mapValues(_.map { // if an argument is a BoxType (Array or Option), but we pass a stream, // change a type as stream to not miss `$` sign in air @@ -172,7 +183,7 @@ object ArrowInliner extends Logging { tree = treeRenamed.rename(shouldRename) // Result could be renamed; take care about that - } yield (tree, fn.ret.map(_.renameVars(shouldRename))) + } yield (tree, fn.ret.map(_.renameVars(shouldRename ++ returnedArrowsShouldRename))) private[inline] def callArrowRet[S: Exports: Arrows: Mangler]( arrow: FuncArrow, @@ -185,12 +196,15 @@ object ArrowInliner extends Logging { for { _ <- Arrows[S].resolved(passArrows) av <- ArrowInliner.inline(arrow, call) - } yield av + // find and get resolved arrows if we return them from the function + returnedArrows = av._2.collect { case VarModel(name, ArrowType(_, _), _) => + name + } + arrowsToSave <- Arrows[S].pickArrows(returnedArrows.toSet) + } yield av -> arrowsToSave ) - (appliedOp, value) = av - - _ <- Exports[S].resolved(call.exportTo.map(_.name).zip(value).toMap) - - } yield appliedOp -> value - + ((appliedOp, values), arrowsToSave) = av + _ <- Arrows[S].resolved(arrowsToSave) + _ <- Exports[S].resolved(call.exportTo.map(_.name).zip(values).toMap) + } yield appliedOp -> values } diff --git a/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala b/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala index 99712d08..927b0c51 100644 --- a/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala @@ -4,9 +4,10 @@ import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler} import aqua.model.* import aqua.model.inline.RawValueInliner.collectionToModel import aqua.model.inline.raw.{CallArrowRawInliner, CollectionRawInliner} +import aqua.raw.arrow.FuncRaw import aqua.raw.ops.* import aqua.raw.value.* -import aqua.types.{ArrayType, BoxType, CanonStreamType, StreamType} +import aqua.types.{ArrayType, ArrowType, BoxType, CanonStreamType, StreamType} import cats.syntax.traverse.* import cats.syntax.applicative.* import cats.instances.list.* diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala index f1f7da3b..f6cf2702 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala @@ -1,11 +1,12 @@ package aqua.model.inline.raw import aqua.model.inline.Inline.parDesugarPrefixOpt -import aqua.model.{CallServiceModel, SeqModel, ValueModel, VarModel} +import aqua.model.{CallServiceModel, FuncArrow, SeqModel, ValueModel, VarModel} import aqua.model.inline.{ArrowInliner, Inline, TagInliner} import aqua.model.inline.RawValueInliner.{callToModel, valueToModel} import aqua.model.inline.state.{Arrows, Exports, Mangler} import aqua.raw.ops.Call +import aqua.types.ArrowType import aqua.raw.value.CallArrowRaw import cats.data.{Chain, State} import scribe.Logging @@ -42,31 +43,58 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { */ val funcName = value.ability.fold(value.name)(_ + "." + value.name) logger.trace(s" $funcName") - Arrows[S].arrows.flatMap(arrows => - arrows.get(funcName) match { - case Some(fn) => - logger.trace(Console.YELLOW + s"Call arrow $funcName" + Console.RESET) - callToModel(call, false).flatMap { case (cm, p) => - ArrowInliner - .callArrowRet(fn, cm) - .map { case (body, vars) => - vars -> Inline( - ListMap.empty, - Chain.one(SeqModel.wrap(p.toList :+ body: _*)) - ) - } - } - case None => - logger.error( - s"Inlining, cannot find arrow ${funcName}, available: ${arrows.keys - .mkString(", ")}" - ) - State.pure(Nil -> Inline.empty) - } - ) + + resolveArrow(funcName, call) } } + private def resolveFuncArrow[S: Mangler: Exports: Arrows](fn: FuncArrow, call: Call) = { + logger.trace(Console.YELLOW + s"Call arrow ${fn.funcName}" + Console.RESET) + callToModel(call, false).flatMap { case (cm, p) => + ArrowInliner + .callArrowRet(fn, cm) + .map { case (body, vars) => + vars -> Inline( + ListMap.empty, + Chain.one(SeqModel.wrap(p.toList :+ body: _*)) + ) + } + } + } + + private def resolveArrow[S: Mangler: Exports: Arrows](funcName: String, call: Call) = + Arrows[S].arrows.flatMap(arrows => + arrows.get(funcName) match { + case Some(fn) => + resolveFuncArrow(fn, call) + case None => + Exports[S].exports.flatMap { exps => + // if there is no arrow, check if it is stored in Exports as variable and try to resolve it + exps.get(funcName) match { + case Some(VarModel(name, ArrowType(_, _), _)) => + Arrows[S].arrows.flatMap(arrows => + arrows.get(name) match { + case Some(fn) => + resolveFuncArrow(fn, call) + case _ => + logger.error( + s"Inlining, cannot find arrow $funcName, available: ${arrows.keys + .mkString(", ")}" + ) + State.pure(Nil -> Inline.empty) + } + ) + case _ => + logger.error( + s"Inlining, cannot find arrow $funcName, available: ${arrows.keys + .mkString(", ")}" + ) + State.pure(Nil -> Inline.empty) + } + } + } + ) + override def apply[S: Mangler: Exports: Arrows]( raw: CallArrowRaw, propertiesAllowed: Boolean diff --git a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala index 0896a0fd..3a359b7e 100644 --- a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala +++ b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala @@ -3,7 +3,7 @@ package aqua.raw.ops import aqua.raw.Raw import aqua.raw.arrow.FuncRaw import aqua.raw.ops.RawTag.Tree -import aqua.raw.value.{CallArrowRaw, ValueRaw} +import aqua.raw.value.{CallArrowRaw, ValueRaw, VarRaw} import aqua.tree.{TreeNode, TreeNodeCompanion} import aqua.types.{ArrowType, ProductType} import cats.{Eval, Show} @@ -104,7 +104,8 @@ case class MatchMismatchTag(left: ValueRaw, right: ValueRaw, shouldMatch: Boolea MatchMismatchTag(left.map(f), right.map(f), shouldMatch) } -case class ForTag(item: String, iterable: ValueRaw, mode: Option[ForTag.Mode] = None) extends SeqGroupTag { +case class ForTag(item: String, iterable: ValueRaw, mode: Option[ForTag.Mode] = None) + extends SeqGroupTag { override def restrictsVarNames: Set[String] = Set(item) @@ -195,6 +196,9 @@ case class ClosureTag( detach: Boolean ) extends NoExecTag { + override def renameExports(map: Map[String, String]): RawTag = + copy(func = func.copy(name = map.getOrElse(func.name, func.name))) + override def mapValues(f: ValueRaw => ValueRaw): RawTag = copy( func.copy(arrow = diff --git a/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala index bde95073..34e4d3b7 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala @@ -3,14 +3,14 @@ package aqua.parser.expr.func import aqua.parser.Expr import aqua.parser.expr.func.DeclareStreamExpr import aqua.parser.lexer.Token.* -import aqua.parser.lexer.{Name, Token, TypeToken} +import aqua.parser.lexer.{DataTypeToken, Name, Token, TypeToken} import aqua.parser.lift.LiftParser -import cats.parse.Parser -import cats.{~>, Comonad} +import cats.parse.Parser as P +import cats.{Comonad, ~>} import aqua.parser.lift.Span import aqua.parser.lift.Span.{P0ToSpan, PToSpan} -case class DeclareStreamExpr[F[_]](name: Name[F], `type`: TypeToken[F]) +case class DeclareStreamExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends Expr[F](DeclareStreamExpr, name) { override def mapK[K[_]: Comonad](fk: F ~> K): DeclareStreamExpr[K] = @@ -19,8 +19,8 @@ case class DeclareStreamExpr[F[_]](name: Name[F], `type`: TypeToken[F]) object DeclareStreamExpr extends Expr.Leaf { - override val p: Parser[DeclareStreamExpr[Span.S]] = - ((Name.p <* ` : `) ~ TypeToken.`typedef`).map { case (name, t) => + override val p: P[DeclareStreamExpr[Span.S]] = + ((Name.p <* ` : `) ~ DataTypeToken.`datatypedef`).map { case (name, t) => DeclareStreamExpr(name, t) } diff --git a/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala index 543028f1..c33a1600 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala @@ -20,6 +20,7 @@ case class IfExpr[F[_]](left: ValueToken[F], eqOp: EqOp[F], right: ValueToken[F] object IfExpr extends Expr.AndIndented { + // list of expressions that can be used inside this block override def validChildren: List[Expr.Lexem] = ForExpr.validChildren override val p: P[IfExpr[Span.S]] = diff --git a/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala b/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala index 0cf3b882..6055eb12 100644 --- a/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala +++ b/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala @@ -10,7 +10,7 @@ import cats.syntax.comonad.* import cats.syntax.functor.* import cats.~> import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{P0ToSpan, PToSpan, S} sealed trait TypeToken[S[_]] extends Token[S] { def mapK[K[_]: Comonad](fk: S ~> K): TypeToken[K] @@ -102,7 +102,7 @@ object BasicTypeToken { case class ArrowTypeToken[S[_]: Comonad]( override val unit: S[Unit], args: List[(Option[Name[S]], TypeToken[S])], - res: List[DataTypeToken[S]] + res: List[TypeToken[S]] ) extends TypeToken[S] { override def as[T](v: T): S[T] = unit.as(v) @@ -117,9 +117,15 @@ case class ArrowTypeToken[S[_]: Comonad]( object ArrowTypeToken { + def typeDef(): P[TypeToken[S]] = P.defer(TypeToken.`typedef`.between(`(`, `)`).backtrack | TypeToken.`typedef`) + + def returnDef(): P[List[TypeToken[S]]] = comma( + typeDef().backtrack + ).map(_.toList) + def `arrowdef`(argTypeP: P[TypeToken[Span.S]]): P[ArrowTypeToken[Span.S]] = (comma0(argTypeP).with1 ~ ` -> `.lift ~ - (comma(DataTypeToken.`datatypedef`).map(_.toList) + (returnDef().backtrack | `()`.as(Nil))).map { case ((args, point), res) ⇒ ArrowTypeToken(point, args.map(Option.empty[Name[Span.S]] -> _), res) } @@ -129,7 +135,7 @@ object ArrowTypeToken { (Name.p.map(Option(_)) ~ (` : ` *> (argTypeP | argTypeP.between(`(`, `)`)))) .surroundedBy(`/s*`) ) <* (`/s*` *> `)` <* ` `.?)) ~ - (` -> ` *> comma(DataTypeToken.`datatypedef`)).?).map { case ((point, args), res) => + (` -> ` *> returnDef()).?).map { case ((point, args), res) => ArrowTypeToken(point, args, res.toList.flatMap(_.toList)) } } diff --git a/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala b/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala index 8f9a1100..18478bba 100644 --- a/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala @@ -4,6 +4,7 @@ import aqua.parser.lift.LiftParser.Implicits.idLiftParser import aqua.types.ScalarType import aqua.types.ScalarType.u32 import cats.Id +import cats.parse.Parser import org.scalatest.EitherValues import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -21,9 +22,61 @@ class TypeTokenSpec extends AnyFlatSpec with Matchers with EitherValues { BasicTypeToken.`basictypedef`.parseAll("()").isLeft should be(true) } + "Return type" should "parse" in { + + def typedef(str: String) = + ArrowTypeToken.typeDef().parseAll(str).value.mapK(spanToId) + + def returndef(str: String) = + ArrowTypeToken.returnDef().parseAll(str).value.map(_.mapK(spanToId)) + + typedef("(A -> ())") should be( + ArrowTypeToken[Id]((), List((None, CustomTypeToken[Id]("A"))), Nil) + ) + typedef("(A -> B)") should be( + ArrowTypeToken[Id]((), List((None, CustomTypeToken[Id]("A"))), List(CustomTypeToken[Id]("B"))) + ) + + returndef("(A -> B), (C -> D)") should be( + List( + ArrowTypeToken[Id]( + (), + (None, CustomTypeToken[Id]("A")) :: Nil, + List(CustomTypeToken[Id]("B")) + ), + ArrowTypeToken[Id]( + (), + (None, CustomTypeToken[Id]("C")) :: Nil, + List(CustomTypeToken[Id]("D")) + ) + ) + ) + + returndef("A, (B, C -> D, E), F -> G, H") should be( + List( + CustomTypeToken[Id]("A"), + ArrowTypeToken[Id]( + (), + (None, CustomTypeToken[Id]("B")) :: (None, CustomTypeToken[Id]("C")) :: Nil, + List(CustomTypeToken[Id]("D"), CustomTypeToken[Id]("E")) + ), + ArrowTypeToken[Id]( + (), + (None, CustomTypeToken[Id]("F")) :: Nil, + List(CustomTypeToken[Id]("G"), CustomTypeToken[Id]("H")) + ) + ) + ) + } + "Arrow type" should "parse" in { - def arrowdef(str: String) = ArrowTypeToken.`arrowdef`(DataTypeToken.`datatypedef`).parseAll(str).value.mapK(spanToId) - def arrowWithNames(str: String) = ArrowTypeToken.`arrowWithNames`(DataTypeToken.`datatypedef`).parseAll(str).value.mapK(spanToId) + def arrowdef(str: String) = + ArrowTypeToken.`arrowdef`(DataTypeToken.`datatypedef`).parseAll(str).value.mapK(spanToId) + def arrowWithNames(str: String) = ArrowTypeToken + .`arrowWithNames`(DataTypeToken.`datatypedef`) + .parseAll(str) + .value + .mapK(spanToId) arrowdef("-> B") should be( ArrowTypeToken[Id]((), Nil, List(CustomTypeToken[Id]("B"))) @@ -36,6 +89,53 @@ class TypeTokenSpec extends AnyFlatSpec with Matchers with EitherValues { ) ) + arrowdef("A -> B -> C") should be( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("A")) :: Nil, + List( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("B")) :: Nil, + List(CustomTypeToken[Id]("C")) + ) + ) + ) + ) + + arrowdef("A -> B, C -> D") should be( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("A")) :: Nil, + List( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("B")) :: (None -> CustomTypeToken[Id]("C")) :: Nil, + List(CustomTypeToken[Id]("D")) + ) + ) + ) + ) + + arrowdef("A -> (B -> F), (C -> D, E)") should be( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("A")) :: Nil, + List( + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("B")) :: Nil, + CustomTypeToken[Id]("F") :: Nil + ), + ArrowTypeToken[Id]( + (), + (None -> CustomTypeToken[Id]("C")) :: Nil, + CustomTypeToken[Id]("D") :: CustomTypeToken[Id]("E") :: Nil + ) + ) + ) + ) + arrowWithNames("(a: A) -> B") should be( ArrowTypeToken[Id]( (), diff --git a/semantics/src/main/scala/aqua/semantics/expr/func/AssignmentSem.scala b/semantics/src/main/scala/aqua/semantics/expr/func/AssignmentSem.scala index df57be3f..d903c79e 100644 --- a/semantics/src/main/scala/aqua/semantics/expr/func/AssignmentSem.scala +++ b/semantics/src/main/scala/aqua/semantics/expr/func/AssignmentSem.scala @@ -1,8 +1,11 @@ package aqua.semantics.expr.func import aqua.raw.Raw -import aqua.raw.ops.{AssignmentTag, FuncOp} +import aqua.types.ArrowType +import aqua.raw.value.CallArrowRaw +import aqua.raw.ops.{AssignmentTag, ClosureTag, FuncOp} import aqua.parser.expr.func.AssignmentExpr +import aqua.raw.arrow.FuncRaw import aqua.semantics.Prog import aqua.semantics.rules.ValuesAlgebra import aqua.semantics.rules.names.NamesAlgebra @@ -19,10 +22,19 @@ class AssignmentSem[S[_]](val expr: AssignmentExpr[S]) extends AnyVal { ): Prog[Alg, Raw] = V.valueToRaw(expr.value).flatMap { case Some(vm) => - N.derive(expr.variable, vm.`type`, vm.varNames) as (AssignmentTag( - vm, - expr.variable.value - ).funcOpLeaf: Raw) + vm.`type` match { + case at @ ArrowType(_, _) => + N.defineArrow(expr.variable, at, false) as (AssignmentTag( + vm, + expr.variable.value + ).funcOpLeaf: Raw) + case _ => + N.derive(expr.variable, vm.`type`, vm.varNames) as (AssignmentTag( + vm, + expr.variable.value + ).funcOpLeaf: Raw) + } + case _ => Raw.error("Cannot resolve assignment type").pure[Alg] } diff --git a/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala b/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala index 1654f40d..f67307dd 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala @@ -65,17 +65,23 @@ class NamesInterpreter[S[_], X](implicit lens: Lens[X, NamesState[S]], error: Re case Some(g) => modify(st => st.copy(locations = st.locations :+ (name, g))).map(_ => Option(g.tokenType)) case None => - getState.flatMap(st => - report( - name, - Levenshtein.genMessage( - s"Name '${name.value}' not found in scope", - name.value, - st.allNames.toList + // check if we have arrow in variable + readName(name.value).flatMap { + case Some(tt@TokenTypeInfo(_, at@ArrowType(_, _))) => + modify(st => st.copy(locations = st.locations :+ (name, tt))).map(_ => Option(at)) + case _ => + getState.flatMap(st => + report( + name, + Levenshtein.genMessage( + s"Name '${name.value}' not found in scope", + name.value, + st.allNames.toList + ) + ) + .as(Option.empty[ArrowType]) ) - ) - .as(Option.empty[ArrowType]) - ) + } } def readArrowHelper(name: String): SX[Option[TokenArrowInfo[S]]] = diff --git a/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala b/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala index 8955d7b3..c9462638 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala @@ -172,7 +172,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re ensureTypeMatches(op.fields.lookup(fieldName).getOrElse(op), t, value.`type`) case None => report(op, s"No field with name '$fieldName' in $rootT").as(false) } - }.map(res => if (res.toList.fold(true)(_ && _)) Some(IntoCopyRaw(st, fields)) else None) + }.map(res => if (res.forall(identity)) Some(IntoCopyRaw(st, fields)) else None) case _ => report(op, s"Expected $rootT to be a data type").as(None) @@ -230,7 +230,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re if (expected.acceptsValueOf(givenType)) State.pure(true) else { (expected, givenType) match { - case (StructType(n, valueFields), StructType(typeName, typeFields)) => + case (StructType(n, valueFields), StructType(_, typeFields)) => // value can have more fields if (valueFields.length < typeFields.length) { report( @@ -253,7 +253,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re s"Wrong value type, expected: $expected, given: $givenType" ).as(false) } - }.map(_.toList.fold(true)(_ && _)) + }.map(_.forall(identity)) } case _ => val notes = @@ -287,7 +287,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re else report( 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) override def beginArrowScope(token: ArrowTypeToken[S]): State[X, ArrowType] = @@ -362,7 +362,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re frame.arrowType.codomain.toList .lazyZip(values.toList) .foldLeft[Either[(Token[S], String, Boolean), List[ValueRaw]]](Right(Nil)) { - case (acc, (returnType, (token, returnValue))) => + case (acc, (returnType, (_, returnValue))) => acc.flatMap { a => if (!returnType.acceptsValueOf(returnValue.`type`)) Left( @@ -372,7 +372,7 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re .headOption .getOrElse(values.last) ._1, - s"Wrong value type, expected: ${returnType}, given: ${returnValue.`type`}", + s"Wrong value type, expected: $returnType, given: ${returnValue.`type`}", false ) )