Skip to content

Commit 15a4836

Browse files
petar-dambovalievalbttx
authored andcommitted
fix: typed const conversion validation (#3117)
During preprocessing, validates if typed constants are convertible. Fixes [issue](#2681) Typed constants are convertible only in a lossless way. That means that we can convert floats to integers if the fractional part of the float is 0.
1 parent 59acb38 commit 15a4836

File tree

6 files changed

+515
-8
lines changed

6 files changed

+515
-8
lines changed

gnovm/pkg/gnolang/gno_test.go

+130
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,136 @@ func TestBuiltinIdentifiersShadowing(t *testing.T) {
129129
}
130130
}
131131

132+
func TestConvertTo(t *testing.T) {
133+
t.Parallel()
134+
135+
testFunc := func(source, msg string) {
136+
defer func() {
137+
if len(msg) == 0 {
138+
return
139+
}
140+
141+
r := recover()
142+
143+
if r == nil {
144+
t.Fail()
145+
}
146+
147+
err := r.(*PreprocessError)
148+
c := strings.Contains(err.Error(), msg)
149+
if !c {
150+
t.Fatalf(`expected "%s", got "%s"`, msg, r)
151+
}
152+
}()
153+
154+
m := NewMachine("test", nil)
155+
156+
n := MustParseFile("main.go", source)
157+
m.RunFiles(n)
158+
m.RunMain()
159+
}
160+
161+
type cases struct {
162+
source string
163+
msg string
164+
}
165+
166+
tests := []cases{
167+
{
168+
`package test
169+
170+
func main() {
171+
const a int = -1
172+
println(uint(a))
173+
}`,
174+
`test/main.go:5:13: cannot convert constant of type IntKind to UintKind`,
175+
},
176+
{
177+
`package test
178+
179+
func main() {
180+
const a int = -1
181+
println(uint8(a))
182+
}`,
183+
`test/main.go:5:13: cannot convert constant of type IntKind to Uint8Kind`,
184+
},
185+
{
186+
`package test
187+
188+
func main() {
189+
const a int = -1
190+
println(uint16(a))
191+
}`,
192+
`test/main.go:5:13: cannot convert constant of type IntKind to Uint16Kind`,
193+
},
194+
{
195+
`package test
196+
197+
func main() {
198+
const a int = -1
199+
println(uint32(a))
200+
}`,
201+
`test/main.go:5:13: cannot convert constant of type IntKind to Uint32Kind`,
202+
},
203+
{
204+
`package test
205+
206+
func main() {
207+
const a int = -1
208+
println(uint64(a))
209+
}`,
210+
`test/main.go:5:13: cannot convert constant of type IntKind to Uint64Kind`,
211+
},
212+
{
213+
`package test
214+
215+
func main() {
216+
const a float32 = 1.5
217+
println(int32(a))
218+
}`,
219+
`test/main.go:5:13: cannot convert constant of type Float32Kind to Int32Kind`,
220+
},
221+
{
222+
`package test
223+
224+
func main() {
225+
println(int32(1.5))
226+
}`,
227+
`test/main.go:4:13: cannot convert (const (1.5 <untyped> bigdec)) to integer type`,
228+
},
229+
{
230+
`package test
231+
232+
func main() {
233+
const a float64 = 1.5
234+
println(int64(a))
235+
}`,
236+
`test/main.go:5:13: cannot convert constant of type Float64Kind to Int64Kind`,
237+
},
238+
{
239+
`package test
240+
241+
func main() {
242+
println(int64(1.5))
243+
}`,
244+
`test/main.go:4:13: cannot convert (const (1.5 <untyped> bigdec)) to integer type`,
245+
},
246+
{
247+
`package test
248+
249+
func main() {
250+
const f = float64(1.0)
251+
println(int64(f))
252+
}`,
253+
``,
254+
},
255+
}
256+
257+
for _, tc := range tests {
258+
testFunc(tc.source, tc.msg)
259+
}
260+
}
261+
132262
// run empty main().
133263
func TestRunEmptyMain(t *testing.T) {
134264
t.Parallel()

gnovm/pkg/gnolang/op_expressions.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,6 @@ func (m *Machine) doOpFuncLit() {
800800
func (m *Machine) doOpConvert() {
801801
xv := m.PopValue()
802802
t := m.PopValue().GetType()
803-
ConvertTo(m.Alloc, m.Store, xv, t)
803+
ConvertTo(m.Alloc, m.Store, xv, t, false)
804804
m.PushValue(*xv)
805805
}

gnovm/pkg/gnolang/preprocess.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3656,7 +3656,7 @@ func convertConst(store Store, last BlockNode, cx *ConstExpr, t Type) {
36563656
setConstAttrs(cx)
36573657
} else if t != nil {
36583658
// e.g. a named type or uint8 type to int for indexing.
3659-
ConvertTo(nilAllocator, store, &cx.TypedValue, t)
3659+
ConvertTo(nilAllocator, store, &cx.TypedValue, t, true)
36603660
setConstAttrs(cx)
36613661
}
36623662
}

gnovm/pkg/gnolang/values.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1207,7 +1207,7 @@ func (tv *TypedValue) SetInt(n int) {
12071207

12081208
func (tv *TypedValue) ConvertGetInt() int {
12091209
var store Store = nil // not used
1210-
ConvertTo(nilAllocator, store, tv, IntType)
1210+
ConvertTo(nilAllocator, store, tv, IntType, false)
12111211
return tv.GetInt()
12121212
}
12131213

0 commit comments

Comments
 (0)