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

Check inferred type against ascription in variable declaration #935

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ final class MethodNotFound(message: String, source: Option[SourceContext] = None

final class NonApplicableMethod(message: String, source: Option[SourceContext] = None)
extends TyperException(message, source)

final class UnexpectedType(message: String, source: Option[SourceContext] = None)
extends TyperException(message, source)
18 changes: 15 additions & 3 deletions sc/shared/src/main/scala/sigmastate/lang/SigmaTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,21 @@ class SigmaTyper(val builder: SigmaBuilder,
} yield res
node.getOrElse(mkMethodCall(global, method, args, EmptySubst).withPropagatedSrcCtx(srcCtx))
}

/**
* Rewrite tree to typed tree. Checks constituent names and types. Uses
* the env map to resolve bound variables and their types.
*/
def assignType(env: Map[String, SType],
bound: SValue,
expected: Option[SType] = None): SValue = ( bound match {
expected: Option[SType] = None): SValue = { val typedValue = (bound match {
case Block(bs, res) =>
var curEnv = env
val bs1 = ArrayBuffer[Val]()
for (v @ Val(n, _, b) <- bs) {
for (v @ Val(n, givenTpe, b) <- bs) {
if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}", v.sourceContext)
val b1 = assignType(curEnv, b)
val expectedTpe = if (givenTpe != NoType) Some(givenTpe) else None
val b1 = assignType(curEnv, b, expectedTpe)
curEnv = curEnv + (n -> b1.tpe)
builder.currentSrcCtx.withValue(v.sourceContext) {
bs1 += mkVal(n, b1.tpe, b1)
Expand Down Expand Up @@ -518,6 +520,16 @@ class SigmaTyper(val builder: SigmaBuilder,
v => s"Errors found while assigning types to expression $bound: $v assigned NoType")
.withEnsuredSrcCtx(bound.sourceContext)

expected match {
case Some(expectedTpe) =>
if (expectedTpe != typedValue.tpe)
throw new UnexpectedType(
s"expression $bound was expected to have type: $expectedTpe but has type: ${typedValue.tpe}", bound.sourceContext.toOption)
case None => {}
}

typedValue
}
def assignConcreteCollection(cc: ConcreteCollection[SType], newItems: Seq[Value[SType]]) = {
val types = newItems.map(_.tpe).distinct
val tItem = if (cc.items.isEmpty) {
Expand Down
10 changes: 10 additions & 0 deletions sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,14 @@ class SigmaTyperTest extends AnyPropSpec
)
typecheck(customEnv, "substConstants(scriptBytes, positions, newVals)") shouldBe SByteArray
}

property("Inferred - Ascription mismatch") {
val code =
s"""{
| val price: Long = 1.toBigInt
| price
|}""".stripMargin

typefail(env, code, 2, 22)
}
}
Loading