Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 4 additions & 1 deletion gnovm/pkg/gnolang/type_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,10 @@ func (x *BinaryExpr) AssertCompatible(lt, rt Type) {
case EQL, NEQ:
assertComparable(xt, dt)
if !isUntyped(xt) && !isUntyped(dt) {
assertAssignableTo(x, xt, dt)
err := checkAssignableTo(x, xt, dt)
if err != nil {
panic(fmt.Sprintf("invalid operation: %v (mismatched types %v and %v)", x, xt, dt))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-wise, we should maybe avoid panicking with the whole expression, as it might be very deep. what about making the error "types %v and %v are not comparable"?

}
Comment on lines 740 to 746
Copy link
Member

@MikaelVallenet MikaelVallenet Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we wrap the error in the panic message ?
We may loose some information isn't ? Looks fine to me since the message indicate the position and show both types so it's enough to understand where & what is the problem.

Also in preprocess.go we show this message, should we have make the panic messages similar for consistence ?

if checkAssignableTo(n, tt, st) != nil {
	panic(
		fmt.Sprintf(
			"cannot use %v (value of type %s) as %s value in assignment",
			valueExpr.String(),
			tt.String(),
			st.String(),
		),
	)
}

Also what about editing directly assertAssignableTo to print your improved message instead doing it specifically at one place.

Copy link
Contributor Author

@ltzmaxwell ltzmaxwell Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we wrap the error in the panic message ?

I think the low-level message is useful for debugging, but not for end users. We should log it instead of returning. :51625b8

Also in preprocess.go we show this message, should we have make the panic messages similar for consistence ?

it looks the correct, see gnovm/tests/files/assign33.gno.

Also what about editing directly assertAssignableTo to print your improved message instead doing it specifically at one place.

for me it still make sense that it provides lower-level infos.

}
case LSS, LEQ, GTR, GEQ:
if checker, ok := binaryChecker[x.Op]; ok {
Expand Down
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_iface_5.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
}

// Error:
// main/cmp_iface_5.gno:19:5-23: int64 does not implement .uverse.error (missing method Error)
// main/cmp_iface_5.gno:19:5-23: invalid operation: errCmp<VPBlock(4,1)> == (const (1 int64)) (mismatched types int64 and .uverse.error)

// TypeCheckError:
// main/cmp_iface_5.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_pointer.gno
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func main() {
}

// Error:
// main/cmp_pointer.gno:19:27-38: cannot use main.Person as main.Worker without explicit conversion
// main/cmp_pointer.gno:19:27-38: invalid operation: p1<VPBlock(1,0)> == p2Ptr<VPBlock(1,2)> (mismatched types *main.Person and *main.Worker)

// TypeCheckError:
// main/cmp_pointer.gno:19:33: invalid operation: p1 == p2Ptr (mismatched types *Person and *Worker)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_slice_4.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ func main() {
}

// Error:
// main/cmp_slice_4.gno:6:10-23: cannot use int as string
// main/cmp_slice_4.gno:6:10-23: invalid operation: a<VPBlock(1,1)> == expected<VPBlock(1,0)> (mismatched types int and string)

// TypeCheckError:
// main/cmp_slice_4.gno:6:15: invalid operation: a == expected (mismatched types int and string)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_struct_b.gno
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
}

// Error:
// main/cmp_struct_b.gno:15:10-18: cannot use main.foo as main.bar without explicit conversion
// main/cmp_struct_b.gno:15:10-18: invalid operation: fa<VPBlock(1,0)> == bb<VPBlock(1,1)> (mismatched types main.foo and main.bar)

// TypeCheckError:
// main/cmp_struct_b.gno:15:16: invalid operation: fa == bb (mismatched types foo and bar)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_struct_c1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
}

// Error:
// main/cmp_struct_c1.gno:15:10-18: cannot use main.bar as main.foo without explicit conversion
// main/cmp_struct_c1.gno:15:10-18: invalid operation: bb<VPBlock(1,1)> == fa<VPBlock(1,0)> (mismatched types main.bar and main.foo)

// TypeCheckError:
// main/cmp_struct_c1.gno:15:16: invalid operation: bb == fa (mismatched types bar and foo)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/cmp_struct_g.gno
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
}

// Error:
// main/cmp_struct_g.gno:17:25-31: cannot use main.Person as main.Dog without explicit conversion
// main/cmp_struct_g.gno:17:25-31: invalid operation: a<VPBlock(1,0)> == b<VPBlock(1,1)> (mismatched types main.Person and main.Dog)

// TypeCheckError:
// main/cmp_struct_g.gno:17:30: invalid operation: a == b (mismatched types Person and Dog)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a0.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ func main() {
}

// Error:
// main/eql_0a0.gno:5:10-27: cannot use int as int8
// main/eql_0a0.gno:5:10-27: invalid operation: (const (1 int)) == (const (1 int8)) (mismatched types int and int8)

// TypeCheckError:
// main/eql_0a0.gno:5:20: invalid operation: int(1) == int8(1) (mismatched types int and int8)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a02.gno
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func main() {
}

// Error:
// main/eql_0a02.gno:7:10-21: cannot use *int as string
// main/eql_0a02.gno:7:10-21: invalid operation: intPtr<VPBlock(1,0)> == s<VPBlock(1,1)> (mismatched types *int and string)

// TypeCheckError:
// main/eql_0a02.gno:7:20: invalid operation: intPtr == s (mismatched types *int and string)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a03.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func main() {
}

// Error:
// main/eql_0a03.gno:8:10-22: cannot use int8 as int
// main/eql_0a03.gno:8:10-22: invalid operation: intPtr<VPBlock(1,0)> == &(i<VPBlock(1,1)>) (mismatched types *int8 and *int)

// TypeCheckError:
// main/eql_0a03.gno:8:20: invalid operation: intPtr == &i (mismatched types *int8 and *int)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ func main() {
}

// Error:
// main/eql_0a1.gno:5:10-27: cannot use int as int8
// main/eql_0a1.gno:5:10-27: invalid operation: (const (1 int)) != (const (1 int8)) (mismatched types int and int8)

// TypeCheckError:
// main/eql_0a1.gno:5:20: invalid operation: int(1) != int8(1) (mismatched types int and int8)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a1a0.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ func main() {
}

// Error:
// main/eql_0a1a0.gno:5:10-24: cannot use uint64 as uint
// main/eql_0a1a0.gno:5:10-24: invalid operation: (const (1 uint64)) == a<VPBlock(1,0)> (mismatched types uint64 and uint)

// TypeCheckError:
// main/eql_0a1a0.gno:5:23: invalid operation: uint64(1) == a (mismatched types uint64 and uint)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a1a1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ func main() {
}

// Error:
// main/eql_0a1a1.gno:5:10-24: cannot use uint as uint64
// main/eql_0a1a1.gno:5:10-24: invalid operation: a<VPBlock(1,0)> == (const (1 uint64)) (mismatched types uint and uint64)

// TypeCheckError:
// main/eql_0a1a1.gno:5:15: invalid operation: a == uint64(1) (mismatched types uint and uint64)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a1f.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ func main() {
}

// Error:
// main/eql_0a1f.gno:6:10-23: cannot use int as string
// main/eql_0a1f.gno:6:10-23: invalid operation: a<VPBlock(1,1)> == expected<VPBlock(1,0)> (mismatched types int and string)

// TypeCheckError:
// main/eql_0a1f.gno:6:15: invalid operation: a == expected (mismatched types int and string)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a1g.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ func main() {
}

// Error:
// main/eql_0a1g.gno:6:10-16: cannot use int as float32
// main/eql_0a1g.gno:6:10-16: invalid operation: a<VPBlock(1,0)> == b<VPBlock(1,1)> (mismatched types int and float32)

// TypeCheckError:
// main/eql_0a1g.gno:6:15: invalid operation: a == b (mismatched types int and float32)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a2.gno
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func main() {
}

// Error:
// main/eql_0a2.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion
// main/eql_0a2.gno:21:10-32: invalid operation: (const (0 main.Error1)) == (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2)

// TypeCheckError:
// main/eql_0a2.gno:21:23: invalid operation: Error1(0) == Error2(0) (mismatched types Error1 and Error2)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a3.gno
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func main() {
}

// Error:
// main/eql_0a3.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion
// main/eql_0a3.gno:21:10-32: invalid operation: (const (0 main.Error1)) != (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2)

// TypeCheckError:
// main/eql_0a3.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0a4.gno
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func main() {
}

// Error:
// main/eql_0a4.gno:21:10-32: cannot use main.Error1 as main.Error2 without explicit conversion
// main/eql_0a4.gno:21:10-32: invalid operation: (const (0 main.Error1)) != (const (0 main.Error2)) (mismatched types main.Error1 and main.Error2)

// TypeCheckError:
// main/eql_0a4.gno:21:23: invalid operation: Error1(0) != Error2(0) (mismatched types Error1 and Error2)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0e0.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
}

// Error:
// main/eql_0e0.gno:23:10-18: cannot use main.Error1 as main.Error2 without explicit conversion
// main/eql_0e0.gno:23:10-18: invalid operation: e1<VPBlock(1,0)> == e2<VPBlock(1,1)> (mismatched types main.Error1 and main.Error2)

// TypeCheckError:
// main/eql_0e0.gno:23:16: invalid operation: e1 == e2 (mismatched types Error1 and Error2)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0e1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
}

// Error:
// main/eql_0e1.gno:23:10-18: cannot use main.Error1 as main.Error2 without explicit conversion
// main/eql_0e1.gno:23:10-18: invalid operation: e1<VPBlock(1,0)> != e2<VPBlock(1,1)> (mismatched types main.Error1 and main.Error2)

// TypeCheckError:
// main/eql_0e1.gno:23:16: invalid operation: e1 != e2 (mismatched types Error1 and Error2)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0f1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {
}

// Error:
// main/eql_0f1.gno:19:5-23: int64 does not implement .uverse.error (missing method Error)
// main/eql_0f1.gno:19:5-23: invalid operation: (const (1 int64)) == errCmp<VPBlock(4,1)> (mismatched types int64 and .uverse.error)

// TypeCheckError:
// main/eql_0f1.gno:19:17: invalid operation: int64(1) == errCmp (mismatched types int64 and error)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0f14.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func main() {
}

// Error:
// main/eql_0f14.gno:10:10-16: cannot use [2]string as [2]int
// main/eql_0f14.gno:10:10-16: invalid operation: a<VPBlock(3,0)> == c<VPBlock(3,1)> (mismatched types [2]string and [2]int)

// TypeCheckError:
// main/eql_0f14.gno:10:15: invalid operation: a == c (mismatched types [2]string and [2]int)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0f30f.gno
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func main() {
}

// Error:
// main/eql_0f30f.gno:7:10-16: cannot use [2]int as [3]int
// main/eql_0f30f.gno:7:10-16: invalid operation: a<VPBlock(3,0)> == b<VPBlock(3,1)> (mismatched types [2]int and [3]int)

// TypeCheckError:
// main/eql_0f30f.gno:7:15: invalid operation: a == b (mismatched types [2]int and [3]int)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0f41.gno
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func main() {
}

// Error:
// main/eql_0f41.gno:27:5-20: main.animal does not implement .uverse.error (missing method Error)
// main/eql_0f41.gno:27:5-20: invalid operation: get<VPBlock(4,2)>() == errCmp<VPBlock(4,3)> (mismatched types main.animal and .uverse.error)

// TypeCheckError:
// main/eql_0f41.gno:27:14: invalid operation: get() == errCmp (mismatched types animal and error)
2 changes: 1 addition & 1 deletion gnovm/tests/files/types/eql_0f8.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
}

// Error:
// main/eql_0f8.gno:19:5-23: int64 does not implement .uverse.error (missing method Error)
// main/eql_0f8.gno:19:5-23: invalid operation: errCmp<VPBlock(4,1)> == (const (1 int64)) (mismatched types int64 and .uverse.error)

// TypeCheckError:
// main/eql_0f8.gno:19:15: invalid operation: errCmp == int64(1) (mismatched types error and int64)
Loading