Skip to content

Commit

Permalink
NODE-2526 Fix IDE highlighting type error (#3777)
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Nov 1, 2022
1 parent a4dd090 commit e9e1e19
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 30 deletions.
7 changes: 7 additions & 0 deletions lang/js/src/main/scala/JsApiUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ object JsApiUtils {
mergeJSObjects(commonDataObj, additionalDataObj)
}

case Expressions.FOLD(_, limit, value, acc, func, _, _) =>
val additionalDataObj = jObj.applyDynamic("apply")(
"name" -> s"FOLD<$limit>",
"args" -> js.Array(serExpr(value), serExpr(acc), func.key.toString: js.Any)
)
mergeJSObjects(commonDataObj, additionalDataObj)

case Expressions.MATCH(_, expr, cases, _, ctxOpt) => {
val additionalDataObj = jObj.applyDynamic("apply")(
"expr" -> serExpr(expr),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,16 @@ object ExpressionCompiler {
.recover { case err => CompilationStepResultExpr(ctx, FAILED_EXPR(), NOTHING, expr, List(err)) }

expr match {
case x: Expressions.CONST_LONG => CompilationStepResultExpr(ctx, CONST_LONG(x.value): EXPR, LONG: FINAL, x: Expressions.EXPR).pure[CompileM]
case x: Expressions.CONST_LONG => CompilationStepResultExpr(ctx, CONST_LONG(x.value), LONG, x).pure[CompileM]
case x: Expressions.CONST_BYTESTR => handlePart(x.value).flatMap(b => liftEither(adjustByteStr(x, b)))
case x: Expressions.CONST_STRING => handlePart(x.value).flatMap(s => liftEither(adjustStr(x, s)))
case x: Expressions.TRUE => CompilationStepResultExpr(ctx, TRUE: EXPR, BOOLEAN: FINAL, x: Expressions.EXPR).pure[CompileM]
case x: Expressions.FALSE => CompilationStepResultExpr(ctx, FALSE: EXPR, BOOLEAN: FINAL, x: Expressions.EXPR).pure[CompileM]
case x: Expressions.TRUE => CompilationStepResultExpr(ctx, TRUE, BOOLEAN, x).pure[CompileM]
case x: Expressions.FALSE => CompilationStepResultExpr(ctx, FALSE, BOOLEAN, x).pure[CompileM]

case x: Expressions.INVALID =>
CompilationStepResultExpr(
ctx,
FAILED_EXPR(): EXPR,
FAILED_EXPR(),
NOTHING,
x: Expressions.EXPR,
List(Generic(x.position.start, x.position.end, x.message))
Expand All @@ -138,7 +138,7 @@ object ExpressionCompiler {
case Expressions.REF(p, key, _, _) => compileRef(p, key, saveExprContext)
case Expressions.FUNCTION_CALL(p, name, args, _, _) => compileFunctionCall(p, name, args, saveExprContext, allowIllFormedStrings)
case Expressions.MATCH(p, ex, cases, _, _) => compileMatch(p, ex, cases.toList, saveExprContext, allowIllFormedStrings)
case Expressions.FOLD(p, limit, list, acc, f, _, _) => compileFold(p, limit, list, acc, f.key)
case f: Expressions.FOLD => compileFold(f)
case Expressions.GENERIC_FUNCTION_CALL(p, e, name, t, _, _) =>
compileGenericFunctionCall(p, e, name, t, saveExprContext, allowIllFormedStrings)
case Expressions.BINARY_OP(p, a, op, b, _, _) =>
Expand Down Expand Up @@ -176,7 +176,8 @@ object ExpressionCompiler {
condWithErr._1.parseNodeExpr,
ifTrue.parseNodeExpr,
ifFalse.parseNodeExpr,
ctxOpt = saveExprContext.toOption(ctx.getSimpleContext())
Some(t),
saveExprContext.toOption(ctx.getSimpleContext())
)
errorList = condWithErr._1.errors ++ ifTrue.errors ++ ifFalse.errors

Expand All @@ -185,7 +186,7 @@ object ExpressionCompiler {
ctx,
IF(condWithErr._1.expr, ifTrue.expr, ifFalse.expr),
t,
parseNodeExpr.copy(resultType = Some(t)),
parseNodeExpr,
errorList
)
} else {
Expand Down Expand Up @@ -507,7 +508,7 @@ object ExpressionCompiler {
compLetResult.parseNodeExpr,
compiledBody.parseNodeExpr,
compiledBody.parseNodeExpr.resultType,
ctxOpt = saveExprContext.toOption(compiledBody.ctx.getSimpleContext())
saveExprContext.toOption(compiledBody.ctx.getSimpleContext())
)
result = if (!compLetResult.dec.isItFailed) {
LET_BLOCK(compLetResult.dec.asInstanceOf[LET], compiledBody.expr)
Expand Down Expand Up @@ -604,7 +605,8 @@ object ExpressionCompiler {
p,
namePart,
compiledArgs.map(_.parseNodeExpr),
ctxOpt = saveExprContext.toOption(ctx.getSimpleContext())
funcCallWithErr._1.map(_._2),
saveExprContext.toOption(ctx.getSimpleContext())
)

result = if (errorList.isEmpty) {
Expand Down Expand Up @@ -647,7 +649,7 @@ object ExpressionCompiler {
ctx,
REF(keyWithErr._1.get),
typeWithErr._1.get,
Expressions.REF(p, keyPart, None, ctxOpt = saveExprContext.toOption(ctx.getSimpleContext()))
Expressions.REF(p, keyPart, typeWithErr._1, saveExprContext.toOption(ctx.getSimpleContext()))
)
} else {
CompilationStepResultExpr(
Expand All @@ -660,23 +662,17 @@ object ExpressionCompiler {
}
} yield result

private def compileFold(
p: Pos,
limit: Int,
list: Expressions.EXPR,
acc: Expressions.EXPR,
func: PART[String]
): CompileM[CompilationStepResultExpr] =
private def compileFold(fold: Expressions.FOLD): CompileM[CompilationStepResultExpr] =
for {
(compiledList, listType, _, compileListErrors) <- compileExpr(list)
name = s"FOLD<$limit>"
(compiledList, listType, _, compileListErrors) <- compileExpr(fold.list)
name = s"FOLD<${fold.limit}>"
listInnerType <- (listType match {
case list: LIST => Right(list.innerType)
case other => Left(Generic(p.start, p.end, s"First $name argument should be List[A], but $other found"))
case other => Left(Generic(fold.position.start, fold.position.end, s"First $name argument should be List[A], but $other found"))
}).toCompileM
(compiledAcc, accType, accRaw, compileAccErrors) <- compileExpr(acc)
funcName <- handlePart(func)
ctx <- get[Id, CompilerContext, CompilationError]
(compiledAcc, accType, _, compileAccErrors) <- compileExpr(fold.acc)
funcName <- handlePart(fold.func.key)
ctx <- get[Id, CompilerContext, CompilationError]
compiledFunc <- ctx
.functionTypeSignaturesByName(funcName, args = 2)
.collectFirst {
Expand All @@ -686,14 +682,14 @@ object ExpressionCompiler {
.getOrElse {
val accTypeStr = if (accType == NOTHING) ANY else accType
val listInnerTypeStr = if (listInnerType == NOTHING) ANY else listInnerType
Left(Generic(p.start, p.end, s"Can't find suitable function $funcName(a: $accTypeStr, b: $listInnerTypeStr) for $name"))
Left(Generic(fold.position.start, fold.position.end, s"Can't find suitable function $funcName(a: $accTypeStr, b: $listInnerTypeStr) for $name"))
}
.toCompileM
_ <- set[Id, CompilerContext, CompilationError](ctx.copy(foldIdx = ctx.foldIdx + 1))
resultType = compiledFunc.args.head._2.asInstanceOf[FINAL]
compiledFold <- {
val unwrapped = CompilerMacro.unwrapFold(ctx.foldIdx, limit, compiledList, compiledAcc, compiledFunc.header)
CompilationStepResultExpr(ctx, unwrapped, resultType, accRaw, compileListErrors ++ compileAccErrors)
val unwrapped = CompilerMacro.unwrapFold(ctx.foldIdx, fold.limit, compiledList, compiledAcc, compiledFunc.header)
CompilationStepResultExpr(ctx, unwrapped, resultType, fold.copy(resultType = Some(resultType)), compileListErrors ++ compileAccErrors)
.asRight[CompilationError]
.toCompileM
}
Expand Down
53 changes: 53 additions & 0 deletions lang/tests-js/src/test/scala/JsAPITest.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import com.wavesplatform.lang.directives.values.{V5, V6}
import utest.*

import scala.scalajs.js.{Array, Dynamic, JSON}

object JsAPITest extends JsTestBase {
private def simpleDApp(result: String): String =
dApp(
Expand Down Expand Up @@ -49,5 +51,56 @@ object JsAPITest extends JsTestBase {
r.userFunctionComplexities ==> Map("f" -> 2)
r.globalVariableComplexities ==> Map("x" -> 1)
}

test("AST result type for declarations") {
val compiled = JsAPI.parseAndCompile(
dApp(
"""
| func sum(acc: List[Int], elem: Int) = acc :+ elem
| let arr = [1, 2, 3, 4, 5]
| let letFold = FOLD<5>(arr, [], sum)
|
| @Callable(i)
| func default() = {
| let letCall = i.caller.toString()
| let letIf = if (true) then 1 else ""
| let letMatch = match letIf {
| case _: Int => true
| case _: String => Address(base58'')
| }
| func funcRef() = letCall
| []
| }
""".stripMargin,
V6
),
3
)
val callables = compiled.dAppAst.annFuncList.asInstanceOf[Array[Dynamic]]

val invocation = callables(0).func.expr.dec.expr.args.asInstanceOf[Array[Dynamic]].apply(0).ref
invocation.name ==> "i"
invocation.resultType.`type` ==> "Invocation"

val letCall = callables(0).func.expr.dec
letCall.name.value ==> "letCall"
letCall.expr.resultType.`type` ==> "String"

val letIf = callables(0).func.expr.body.dec
letIf.name.value ==> "letIf"
JSON.stringify(letIf.expr.resultType.unionTypes) ==> """[{"type":"Int"},{"type":"String"}]"""

val letMatch = callables(0).func.expr.body.body.dec
letMatch.name.value ==> "letMatch"
JSON.stringify(letMatch.expr.resultType.unionTypes) ==> """[{"type":"Boolean"},{"type":"Address"}]"""

val funcRef = callables(0).func.expr.body.body.body.dec
funcRef.name.value ==> "funcRef"
funcRef.expr.resultType.`type` ==> "String"

val letFold = compiled.dAppAst.decList.asInstanceOf[Array[Dynamic]].apply(2)
letFold.name.value ==> "letFold"
JSON.stringify(letFold.expr.resultType) ==> """{"listOf":{"type":"Int"}}"""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ExpressionCompilerWithParserV2Test extends PropSpec {
|else
| false
|
|""".stripMargin
""".stripMargin

val result = compile(script)

Expand All @@ -60,13 +60,13 @@ class ExpressionCompilerWithParserV2Test extends PropSpec {
FUNCTION_CALL(
AnyPos,
PART.VALID(AnyPos, "+"),
List(REF(AnyPos, PART.VALID(AnyPos, "foo"), None, None), REF(AnyPos, PART.VALID(AnyPos, "bar"), None, None)),
None,
List(REF(AnyPos, PART.VALID(AnyPos, "foo"), Some(LONG), None), REF(AnyPos, PART.VALID(AnyPos, "bar"), Some(LONG), None)),
Some(LONG),
None
),
CONST_LONG(AnyPos, 123456, None)
),
None,
Some(BOOLEAN),
None
),
TRUE(AnyPos, None),
Expand Down

0 comments on commit e9e1e19

Please sign in to comment.