Open ASVIEST opened 11 months ago
See also: #172 and specifically https://github.com/nim-lang/RFCs/issues/172#issuecomment-1604745482
Now i think that for it we need special SMT Immediate representation, that generates from NIR, this IR have all that need on SMT analysis of code. For refirement type it in scope where it used and only before refirement type. Example of this IR
var x = "val" # x = StrVal("val")
var y = 4 # y = IntVal(4)
var z = 2.0 # z = FloatVal(2.0) #FP in z3
import std/rationals
var w = 5//7 # w = Rational(5, 7) # RealVal in z3
var f = 5'u32 // 8 # f = Rational(5, 8); f >= 0
var c = {5, 8} # c = Set({5, 8})
for i in 0..<5:
y = 7
# Loop{
# Range { # max and min iter count, can be Unknown, when min == max, loop can be unrolled. when min > 0 we can check invariance of loop body (it preferred than unrolling, because invariant loops becomes 1 expr).
# min: 5
# max: 5
# }
# i = IntConst
# i >= 0
# i < 5
# y = IntVal(7)
# }
var s = @["a", "b", "c"] # SeqVal(@["a", "b", "c"])
if (let x = readline(stdin); x) == "test":
s = @[x]
# If { # can map into z3 if
# entry {
# x = StrVal("test")
# s = SeqVal(@[x])
# }
# else {
# # yes, all elif branches as new if here
# x = StrConst
# s = SeqVal(@["a", "b", "c"]) # when some var was modified in some branch, it's must be modified in other branches
# }
try:
raise newException(CatchableError, "err")
y = 5
except CatchableError:
discard
# try body analysis for raise algorithm:
# make the smt predictions about try body
# haveErr = BoolVal(false)
# any raise just changed haveErr to BoolVal(true)
# if haveErr can be predicted, just select one predicted branch of try,
Result smtir:
# smtir
x = StrVal("val")
y = IntVal(4)
z = FloatVal(2.0)
w = Rational(5, 7)
f = Rational(5, 8)
f >= 0
var c = SetVal({5, 8})
Loop{
Range { # max and min iter count, can be Unknown, when min == max, loop can be unrolled
min: 5
max: 5
}
i = IntConst
i >= 0
i < 5
y = IntVal(7)
}
cond__0 = StrConst
If { # some if's can map into z3 if
cond_ 0 == "test"
entry {
x = StrVal("test")
s = SeqVal(@[x])
}
else {
# yes, all elif branches as new if here
x = StrConst
s = SeqVal(@["a", "b", "c"]) # when some var was modified in some branch, it's must be modified in other branches
}
}
haveErr = BoolConst
Try {
haveErr # is defined after entry
entry {
haveErr = BoolVal(true) # goto else
}
else {
}
Then when in refirement type it will simplified because save only need variables as example we have predicate (in module scope) that y > 0 (about y) smtir become
y = IntVal(4)
Loop{
Range { # max and min iter count, can be Unknown, when min == max, loop can be unrolled
min: 5
max: 5
}
i = IntConst
i >= 0
i < 5
y = IntVal(7)
} # Loop invariant
y = IntVal(4)
y = IntVal(7)
y = IntVal(7)
For so simple cases we can do without SMT at all, but it rarely happens. y > 0 => true
Abstract
Add a refinement type that like concepts, but for values
Motivation
it makes the type system more strict. This can prevent you from making stupid mistakes in your code. Also we can make value based overloading.
Description
For implementing it maybe can be need NIR.
In refinement type must be use small nim subset (using nim VM)
Refinement type body must be also checked for sat, if is sat, then it must gen Error, like:
Refinement type Name dont constraint the type
It not possible to prove all nim syntaxes at compileTime, using the SMT. Not proved at CT refinement it must generate hint likerefinement not proved at compile time
. sample proposal implementationCompile time proving should use SMT solver like Z3.
Code Examples
Backwards Compatibility
No response