diff --git a/semantics/src/main/scala/aqua/semantics/rules/types/TypesChecker.scala b/semantics/src/main/scala/aqua/semantics/rules/types/TypesChecker.scala index ccad1ccc..4b5cc816 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/types/TypesChecker.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/types/TypesChecker.scala @@ -5,9 +5,12 @@ import aqua.semantics.rules.report.ReportAlgebra import aqua.types.{BoxType, StreamType, Type} import cats.data.State +import scala.annotation.tailrec + object TypesChecker { // check if this type can exist in aqua code + @tailrec def checkType[S[_], X](name: Token[S], `type`: Type)(using report: ReportAlgebra[S, State[X, *]]): State[X, Unit] = { `type` match { case StreamType(StreamType(_)) => @@ -21,7 +24,7 @@ object TypesChecker { case _ => State.pure(()) } - case t => + case _ => State.pure(()) } } 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 1ba227ca..23304965 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/types/TypesInterpreter.scala @@ -138,7 +138,8 @@ class TypesInterpreter[S[_], X](using case (field, (fieldName, t: DataType)) => t match { case _: StreamType => - report.error(fieldName, s"Field '$field' has stream type. This is forbidden for data structures.").as(none) + // TODO: move these checks into TypesChecker? + report.error(fieldName, s"Field '$field' has stream type. This is forbidden for data structures").as(none) case _ => TypesChecker.checkType(fieldName, t) >> (field -> t).some.pure[ST] } diff --git a/semantics/src/test/scala/aqua/semantics/TypesCheckerSpec.scala b/semantics/src/test/scala/aqua/semantics/TypesCheckerSpec.scala new file mode 100644 index 00000000..4c7b40f9 --- /dev/null +++ b/semantics/src/test/scala/aqua/semantics/TypesCheckerSpec.scala @@ -0,0 +1,48 @@ +package aqua.semantics + +import aqua.parser.lexer.Name +import aqua.semantics.rules.report.{ReportAlgebra, ReportInterpreter, ReportState} +import aqua.semantics.rules.types.TypesChecker +import aqua.types.{ArrayType, OptionType, ScalarType, StreamType, Type} +import cats.Id +import cats.data.State +import monocle.{Iso, Lens} +import org.scalatest.matchers.should.Matchers +import org.scalatest.Inside +import org.scalatest.flatspec.AnyFlatSpec + +class TypesCheckerSpec extends AnyFlatSpec with Matchers with Inside { + + val emptyR = ReportState[Id]() + + def checkType(t: Type) = { + type Interpreter[A] = State[ReportState[Id], A] + + given Lens[ReportState[Id], ReportState[Id]] = Iso.id[ReportState[Id]] + + given ReportAlgebra[Id, Interpreter] = + new ReportInterpreter[Id, ReportState[Id]] + + TypesChecker.checkType[Id, ReportState[Id]](Name[Id]("t"), t).run(emptyR).value._1.errors.headOption + } + + "checker" should "report an error on invalid types" in { + // **string + checkType(StreamType(StreamType(ScalarType.string))) should not be empty + + // []*string + checkType(ArrayType(StreamType(ScalarType.string))) should not be empty + + // ?*string + checkType(OptionType(StreamType(ScalarType.string))) should not be empty + + // ?[]*string + checkType(OptionType(ArrayType(StreamType(ScalarType.string)))) should not be empty + + // [][]*string + checkType(OptionType(ArrayType(StreamType(ScalarType.string)))) should not be empty + + // string + checkType(ScalarType.string) shouldBe empty + } +} diff --git a/semantics/src/test/scala/aqua/semantics/Utils.scala b/semantics/src/test/scala/aqua/semantics/Utils.scala index b00280be..126e865e 100644 --- a/semantics/src/test/scala/aqua/semantics/Utils.scala +++ b/semantics/src/test/scala/aqua/semantics/Utils.scala @@ -50,6 +50,10 @@ object Utils { prog.apply(emptyS).run(blankCS).value._2 } + def getState(prog: Prog[State[CompilerState[cats.Id], *], Raw]): CompilerState[Id] = { + prog.apply(emptyS).run(blankCS).value._1 + } + def getState( startState: Raw )(prog: Prog[State[CompilerState[cats.Id], *], Raw]): CompilerState[Id] = {