mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-12 17:55:33 +00:00
feat(compiler): Enhance message of type error [LNG-313] (#1033)
This commit is contained in:
parent
ae32f80277
commit
d5cd77bb86
@ -17,6 +17,7 @@ import cats.data.{NonEmptyList, OptionT}
|
|||||||
import cats.instances.list.*
|
import cats.instances.list.*
|
||||||
import cats.syntax.applicative.*
|
import cats.syntax.applicative.*
|
||||||
import cats.syntax.apply.*
|
import cats.syntax.apply.*
|
||||||
|
import cats.syntax.bifunctor.*
|
||||||
import cats.syntax.flatMap.*
|
import cats.syntax.flatMap.*
|
||||||
import cats.syntax.foldable.*
|
import cats.syntax.foldable.*
|
||||||
import cats.syntax.functor.*
|
import cats.syntax.functor.*
|
||||||
@ -136,27 +137,23 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
|
|||||||
reportNamedArgsDuplicates(fields)
|
reportNamedArgsDuplicates(fields)
|
||||||
)
|
)
|
||||||
fieldsGiven <- fields
|
fieldsGiven <- fields
|
||||||
.traverse(arg => OptionT(valueToRaw(arg.argValue)).map(arg.argName.value -> _))
|
.traverse(arg =>
|
||||||
.map(_.toNem) // Take only last value for a field
|
OptionT(valueToRaw(arg.argValue)).map(valueRaw =>
|
||||||
fieldsGivenTypes = fieldsGiven.map(_.`type`)
|
arg.argName.value -> (arg, valueRaw)
|
||||||
generated <- OptionT.fromOption(
|
|
||||||
resolvedType match {
|
|
||||||
case struct: StructType =>
|
|
||||||
(
|
|
||||||
struct.copy(fields = fieldsGivenTypes),
|
|
||||||
MakeStructRaw(fieldsGiven, struct)
|
|
||||||
).some
|
|
||||||
case ability: AbilityType =>
|
|
||||||
(
|
|
||||||
ability.copy(fields = fieldsGivenTypes),
|
|
||||||
AbilityRaw(fieldsGiven, ability)
|
|
||||||
).some
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
(genType, genData) = generated
|
)
|
||||||
|
.map(_.toNem) // Take only last value for a field
|
||||||
|
fieldsGivenRaws = fieldsGiven.map { case (_, raw) => raw }
|
||||||
|
fieldsGivenTypes = fieldsGiven.map(_.map(_.`type`))
|
||||||
|
generated = resolvedType match {
|
||||||
|
case struct: StructType =>
|
||||||
|
MakeStructRaw(fieldsGivenRaws, struct)
|
||||||
|
case ability: AbilityType =>
|
||||||
|
AbilityRaw(fieldsGivenRaws, ability)
|
||||||
|
}
|
||||||
data <- OptionT.whenM(
|
data <- OptionT.whenM(
|
||||||
T.ensureTypeMatches(dvt, resolvedType, genType)
|
T.ensureTypeConstructibleFrom(dvt, resolvedType, fieldsGivenTypes)
|
||||||
)(genData.pure)
|
)(generated.pure)
|
||||||
} yield data).value
|
} yield data).value
|
||||||
|
|
||||||
case ct @ CollectionToken(_, values) =>
|
case ct @ CollectionToken(_, values) =>
|
||||||
|
@ -60,6 +60,22 @@ trait TypesAlgebra[S[_], Alg[_]] {
|
|||||||
|
|
||||||
def ensureTypeMatches(token: Token[S], expected: Type, givenType: Type): Alg[Boolean]
|
def ensureTypeMatches(token: Token[S], expected: Type, givenType: Type): Alg[Boolean]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if given type (ability or struct)
|
||||||
|
* can be constructed from given arguments
|
||||||
|
*
|
||||||
|
* @param token token of construction expression (for error reporting)
|
||||||
|
* @param expected type to construct
|
||||||
|
* @param arguments arguments to construct with (name -> (named arg, type))
|
||||||
|
* @return true if type can be constructed from given arguments
|
||||||
|
* reports error and warnings if necessary
|
||||||
|
*/
|
||||||
|
def ensureTypeConstructibleFrom(
|
||||||
|
token: Token[S],
|
||||||
|
expected: AbilityType | StructType,
|
||||||
|
arguments: NonEmptyMap[String, (NamedArg[S], Type)]
|
||||||
|
): Alg[Boolean]
|
||||||
|
|
||||||
def typeToCollectible(token: Token[S], givenType: Type): OptionT[Alg, CollectibleType]
|
def typeToCollectible(token: Token[S], givenType: Type): OptionT[Alg, CollectibleType]
|
||||||
|
|
||||||
def typeToStream(token: Token[S], givenType: Type): OptionT[Alg, StreamType]
|
def typeToStream(token: Token[S], givenType: Type): OptionT[Alg, StreamType]
|
||||||
|
@ -2,6 +2,7 @@ package aqua.semantics.rules.types
|
|||||||
|
|
||||||
import aqua.parser.lexer.*
|
import aqua.parser.lexer.*
|
||||||
import aqua.raw.value.*
|
import aqua.raw.value.*
|
||||||
|
import aqua.semantics.Levenshtein
|
||||||
import aqua.semantics.rules.StackInterpreter
|
import aqua.semantics.rules.StackInterpreter
|
||||||
import aqua.semantics.rules.locations.{DefinitionInfo, LocationsAlgebra}
|
import aqua.semantics.rules.locations.{DefinitionInfo, LocationsAlgebra}
|
||||||
import aqua.semantics.rules.report.ReportAlgebra
|
import aqua.semantics.rules.report.ReportAlgebra
|
||||||
@ -415,6 +416,47 @@ class TypesInterpreter[S[_], X](using
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def ensureTypeConstructibleFrom(
|
||||||
|
token: Token[S],
|
||||||
|
expected: AbilityType | StructType,
|
||||||
|
arguments: NonEmptyMap[String, (NamedArg[S], Type)]
|
||||||
|
): State[X, Boolean] = for {
|
||||||
|
/* Check that required fields are present
|
||||||
|
among arguments and have correct types */
|
||||||
|
enough <- expected.fields.toNel.traverse { case (name, typ) =>
|
||||||
|
arguments.lookup(name) match {
|
||||||
|
case Some(arg -> givenType) =>
|
||||||
|
ensureTypeMatches(arg.argValue, typ, givenType)
|
||||||
|
case None =>
|
||||||
|
report
|
||||||
|
.error(
|
||||||
|
token,
|
||||||
|
s"Missing argument '$name' of type '$typ'"
|
||||||
|
)
|
||||||
|
.as(false)
|
||||||
|
}
|
||||||
|
}.map(_.forall(identity))
|
||||||
|
expectedKeys = expected.fields.keys.toNonEmptyList
|
||||||
|
/* Report unexpected arguments */
|
||||||
|
_ <- arguments.toNel.traverse_ { case (name, arg -> typ) =>
|
||||||
|
expected.fields.lookup(name) match {
|
||||||
|
case Some(_) => State.pure(())
|
||||||
|
case None =>
|
||||||
|
lazy val similar = Levenshtein
|
||||||
|
.mostSimilar(name, expectedKeys, 3)
|
||||||
|
.map(s => s"'$s'")
|
||||||
|
.mkString(", ")
|
||||||
|
val message =
|
||||||
|
if (enough)
|
||||||
|
s"Unexpected argument '$name'"
|
||||||
|
else
|
||||||
|
s"Unexpected argument '$name', did you mean $similar?"
|
||||||
|
|
||||||
|
report.warning(arg.argName, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} yield enough
|
||||||
|
|
||||||
private def typeTo[T <: Type](
|
private def typeTo[T <: Type](
|
||||||
token: Token[S],
|
token: Token[S],
|
||||||
givenType: Type,
|
givenType: Type,
|
||||||
|
Loading…
Reference in New Issue
Block a user