Compare commits

..

4 Commits

Author SHA1 Message Date
xgopilot
a74ca940e2 feat(reflect): add struct test cases for Indirect function
Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: luoliwoshang <luoliwoshang@users.noreply.github.com>
2025-10-20 02:29:18 +00:00
xgopilot
0c68ae00c9 refactor: rename reflect-indirect to reflectindirect
Follow naming convention of other demo folders (reflectfunc, gotime, etc.)

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: luoliwoshang <luoliwoshang@users.noreply.github.com>
2025-10-17 09:19:20 +00:00
xgopilot
8d6d1b76f2 refactor: move reflect.Indirect test to _demo and use panic()
- Moved test from _cmptest/reflect_indirect/ to _demo/go/reflect-indirect/
- Refactored to use panic() for validation instead of fmt.Println
- Added proper assertions for all test cases

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: luoliwoshang <luoliwoshang@users.noreply.github.com>
2025-10-17 09:06:09 +00:00
xgopilot
e47728b053 feat(reflect): add Indirect function
Implements reflect.Indirect function to support pointer dereferencing.
This function returns the value that a pointer points to, or returns
the value unchanged if it's not a pointer.

Fixes #1354

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: luoliwoshang <luoliwoshang@users.noreply.github.com>
2025-10-17 08:06:30 +00:00
5 changed files with 59 additions and 561 deletions

View File

@@ -1,71 +0,0 @@
package main
import "fmt"
func main() {
// Test 1: int8 overflow wrapping
var i8max int8 = 127
fmt.Printf("int8(127) + 1 = %d\n", i8max+1)
// Test 2: int8 arithmetic edge cases
var a int8 = 100
var b int8 = 50
fmt.Printf("int8(100) + int8(50) = %d\n", a+b)
// Test 3: int8 multiplication overflow
var m int8 = 64
fmt.Printf("int8(64) * 2 = %d\n", m*2)
// Test 4: uint32 to float64 to int32 conversion
var bigUint32 uint32 = 0xFFFFFFFF
fmt.Printf("int32(float64(uint32(0xFFFFFFFF))) = %d\n", int32(float64(bigUint32)))
// Test 5: untyped constant with typed variable
const untypedInt = 42
var i32 int32 = 70000
fmt.Printf("const(42) + int32(70000) = %d\n", untypedInt+i32)
// Test 6: signed to unsigned conversion
var negInt int32 = -1
fmt.Printf("uint32(int32(-1)) = 0x%X\n", uint32(negInt))
// Test 7: unsigned to signed conversion
var bigUint uint32 = 0xFFFFFFFF
fmt.Printf("int32(uint32(0xFFFFFFFF)) = %d\n", int32(bigUint))
// Test 8: sign extension
var i8 int8 = -1
fmt.Printf("int32(int8(-1)) = %d\n", int32(i8))
// Test 9: truncation
var i64 int64 = 0x123456789ABC
fmt.Printf("int32(int64(0x123456789ABC)) = 0x%X\n", uint32(int32(i64)))
// Test 10: more overflow cases
var i8min int8 = -128
fmt.Printf("int8(-128) - 1 = %d\n", i8min-1)
var u8max uint8 = 255
fmt.Printf("uint8(255) + 1 = %d\n", u8max+1)
// Test 11: negation overflow
var n1 int8 = -128
fmt.Printf("-int8(-128) = %d\n", -n1)
// Test 12: division edge case
var d1 int8 = -128
var d2 int8 = -1
fmt.Printf("int8(-128) / int8(-1) = %d\n", d1/d2)
// Test 13: int16 overflow
var i16max int16 = 32767
fmt.Printf("int16(32767) + 1 = %d\n", i16max+1)
// Test 14: uint8 truncation from int32
var negInt8 int32 = -1
fmt.Printf("uint8(int32(-1)) = 0x%X\n", uint8(negInt8))
// Test 15: zero extension
var u8 uint8 = 0xFF
fmt.Printf("uint32(uint8(0xFF)) = 0x%X\n", uint32(u8))
}

View File

@@ -0,0 +1,49 @@
package main
import (
"reflect"
)
func main() {
x := 42
p := &x
// Test 1: Non-pointer value - should return same value
v1 := reflect.Indirect(reflect.ValueOf(x))
if !v1.IsValid() || v1.Interface() != 42 {
panic("Non-pointer test failed: expected 42")
}
// Test 2: Pointer - should dereference
v2 := reflect.Indirect(reflect.ValueOf(p))
if !v2.IsValid() || v2.Interface() != 42 {
panic("Pointer dereference test failed: expected 42")
}
// Test 3: Nil pointer - should return invalid Value
var nilPtr *int
v3 := reflect.Indirect(reflect.ValueOf(nilPtr))
if v3.IsValid() {
panic("Nil pointer test failed: expected invalid Value")
}
// Test 4: Struct value - should return same value
type Person struct {
Name string
Age int
}
person := Person{Name: "Alice", Age: 30}
v4 := reflect.Indirect(reflect.ValueOf(person))
if !v4.IsValid() || v4.Interface().(Person).Name != "Alice" || v4.Interface().(Person).Age != 30 {
panic("Struct value test failed: expected Person{Name: Alice, Age: 30}")
}
// Test 5: Struct pointer - should dereference
personPtr := &Person{Name: "Bob", Age: 25}
v5 := reflect.Indirect(reflect.ValueOf(personPtr))
if !v5.IsValid() || v5.Interface().(Person).Name != "Bob" || v5.Interface().(Person).Age != 25 {
panic("Struct pointer test failed: expected Person{Name: Bob, Age: 25}")
}
println("PASS")
}

View File

@@ -1759,6 +1759,16 @@ func ValueOf(i any) Value {
return unpackEface(i)
}
// Indirect returns the value that v points to.
// If v is a nil pointer, Indirect returns a zero Value.
// If v is not a pointer, Indirect returns v.
func Indirect(v Value) Value {
if v.Kind() != Pointer {
return v
}
return v.Elem()
}
// arrayAt returns the i-th element of p,
// an array whose elements are eltSize bytes wide.
// The array pointed at by p must have at least i+1 elements:

View File

@@ -1,311 +0,0 @@
package gotest
import (
"math"
"testing"
)
// TestIntegerOverflow tests that integer overflow wraps correctly
// Issue #961: Max int8 + 1 should be -128, not 128
func TestIntegerOverflow(t *testing.T) {
// Use variables to avoid compile-time constant overflow detection
var i8max int8 = 127
var i8min int8 = -128
var u8max uint8 = 255
var i16max int16 = 32767
var i16min int16 = -32768
var u16max uint16 = 65535
tests := []struct {
name string
result interface{}
expected interface{}
}{
{"int8 max + 1", i8max + 1, int8(-128)},
{"int8 max + 2", i8max + 2, int8(-127)},
{"int8 min - 1", i8min - 1, int8(127)},
{"int8 min - 2", i8min - 2, int8(126)},
{"uint8 max + 1", u8max + 1, uint8(0)},
{"uint8 max + 2", u8max + 2, uint8(1)},
{"int16 max + 1", i16max + 1, int16(-32768)},
{"int16 min - 1", i16min - 1, int16(32767)},
{"uint16 max + 1", u16max + 1, uint16(0)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.result != tt.expected {
t.Errorf("%s: got %v, want %v", tt.name, tt.result, tt.expected)
}
})
}
}
// TestIntegerOverflowOperations tests various overflow operations
func TestIntegerOverflowOperations(t *testing.T) {
// Multiplication overflow
var m1 int8 = 64
if result := m1 * 2; result != -128 {
t.Errorf("int8(64) * 2 = %d, want -128", result)
}
// Addition boundary
var a1 int8 = 100
var a2 int8 = 50
if result := a1 + a2; result != -106 {
t.Errorf("int8(100) + int8(50) = %d, want -106", result)
}
// Negation overflow
var n1 int8 = -128
if result := -n1; result != -128 {
t.Errorf("-int8(-128) = %d, want -128", result)
}
// Division edge case
var d1 int8 = -128
var d2 int8 = -1
if result := d1 / d2; result != -128 {
t.Errorf("int8(-128) / int8(-1) = %d, want -128", result)
}
}
// TestFloatToIntConversion tests float-to-int conversions
// Note: Go has undefined behavior for out-of-range float-to-int conversions
// These tests document the actual behavior we observe
func TestFloatToIntConversion(t *testing.T) {
// Test normal range conversions (well-defined behavior)
t.Run("normal range", func(t *testing.T) {
input := 123.456
if result := int32(input); result != 123 {
t.Errorf("int32(%v) = %d, want 123", input, result)
}
if result := int8(input); result != 123 {
t.Errorf("int8(%v) = %d, want 123", input, result)
}
if result := uint32(input); result != 123 {
t.Errorf("uint32(%v) = %d, want 123", input, result)
}
})
// Out-of-range conversions have undefined behavior in Go
// We just document what happens but don't assert specific values
t.Run("large positive overflow - undefined behavior", func(t *testing.T) {
input := 1e20
result32 := int32(input)
result8 := int8(input)
resultu32 := uint32(input)
t.Logf("int32(1e20) = %d (undefined behavior)", result32)
t.Logf("int8(1e20) = %d (undefined behavior)", result8)
t.Logf("uint32(1e20) = %d (undefined behavior)", resultu32)
})
t.Run("large negative underflow - undefined behavior", func(t *testing.T) {
input := -1e20
result32 := int32(input)
result8 := int8(input)
resultu32 := uint32(input)
t.Logf("int32(-1e20) = %d (undefined behavior)", result32)
t.Logf("int8(-1e20) = %d (undefined behavior)", result8)
t.Logf("uint32(-1e20) = %d (undefined behavior)", resultu32)
})
t.Run("negative to unsigned - undefined behavior", func(t *testing.T) {
input := -123.456
if result := int32(input); result != -123 {
t.Errorf("int32(%v) = %d, want -123", input, result)
}
if result := int8(input); result != -123 {
t.Errorf("int8(%v) = %d, want -123", input, result)
}
// Negative float to unsigned is undefined behavior
resultu32 := uint32(input)
t.Logf("uint32(-123.456) = %d (undefined behavior)", resultu32)
})
}
// TestUint32ToFloatToInt32 tests the specific bug case from issue #961
// Note: Conversion of out-of-range float to int has undefined behavior in Go
func TestUint32ToFloatToInt32(t *testing.T) {
var bigUint32 uint32 = 0xFFFFFFFF // max uint32
fBig := float64(bigUint32)
result := int32(fBig)
// The float64 value of max uint32 (4294967295.0) is larger than max int32,
// so the conversion has undefined behavior.
// We just document what happens without asserting a specific value.
t.Logf("uint32(0xFFFFFFFF) -> float64 -> int32 = %d (undefined behavior)", result)
t.Logf("float64 value: %f", fBig)
}
// TestFloatSpecialValues tests special float values (Inf, NaN)
// Note: Conversions of Inf and NaN to int have undefined behavior
func TestFloatSpecialValues(t *testing.T) {
// Positive infinity - undefined behavior
fInf := math.Inf(1)
result := int32(fInf)
t.Logf("int32(+Inf) = %d (undefined behavior)", result)
// Negative infinity - undefined behavior
fNegInf := math.Inf(-1)
result = int32(fNegInf)
t.Logf("int32(-Inf) = %d (undefined behavior)", result)
// NaN - behavior is implementation-defined, but should not panic
fNaN := math.NaN()
result = int32(fNaN)
t.Logf("int32(NaN) = %d (undefined behavior, just ensure no panic)", result)
}
// TestSignedUnsignedConversions tests signed/unsigned type conversions
func TestSignedUnsignedConversions(t *testing.T) {
// Negative to unsigned
var negInt int32 = -1
if result := uint32(negInt); result != 0xFFFFFFFF {
t.Errorf("uint32(int32(-1)) = 0x%X, want 0xFFFFFFFF", result)
}
if result := uint8(negInt); result != 0xFF {
t.Errorf("uint8(int32(-1)) = 0x%X, want 0xFF", result)
}
// Large unsigned to signed
var bigUint uint32 = 0xFFFFFFFF
if result := int32(bigUint); result != -1 {
t.Errorf("int32(uint32(0xFFFFFFFF)) = %d, want -1", result)
}
// Truncation
var i64 int64 = 0x123456789ABC
expected := int32(0x56789ABC) // Lower 32 bits
if result := int32(i64); result != expected {
t.Errorf("int32(int64(0x123456789ABC)) = 0x%X, want 0x%X", uint32(result), uint32(expected))
}
}
// TestSignExtensionVsZeroExtension tests sign vs zero extension
func TestSignExtensionVsZeroExtension(t *testing.T) {
// Sign extension for signed types
var i8 int8 = -1
if result := int16(i8); result != -1 {
t.Errorf("int16(int8(-1)) = %d, want -1 (sign extension)", result)
}
if result := int32(i8); result != -1 {
t.Errorf("int32(int8(-1)) = %d, want -1 (sign extension)", result)
}
if result := int64(i8); result != -1 {
t.Errorf("int64(int8(-1)) = %d, want -1 (sign extension)", result)
}
// Zero extension for unsigned types
var u8 uint8 = 0xFF
if result := uint16(u8); result != 0xFF {
t.Errorf("uint16(uint8(0xFF)) = 0x%X, want 0xFF (zero extension)", result)
}
if result := uint32(u8); result != 0xFF {
t.Errorf("uint32(uint8(0xFF)) = 0x%X, want 0xFF (zero extension)", result)
}
}
// TestIntToFloatPrecisionLoss tests precision loss in int-to-float conversions
func TestIntToFloatPrecisionLoss(t *testing.T) {
// 2^53 + 1 exceeds float64 precision
var i1 int64 = 9007199254740993
f1 := float64(i1)
if int64(f1) == i1 {
// This might actually be true on some systems due to rounding
t.Logf("int64(9007199254740993) -> float64 preserves precision (unexpected but valid)")
}
// 2^24 + 1 exceeds float32 precision
var i2 int32 = 16777217
f2 := float32(i2)
if int32(f2) == i2 {
t.Logf("int32(16777217) -> float32 preserves precision (unexpected but valid)")
}
}
// TestIssue961Examples tests the exact code examples from issue #961
// This ensures LLGo produces the same results as standard Go
func TestIssue961Examples(t *testing.T) {
t.Run("int8 overflow example", func(t *testing.T) {
var i8max int8 = 127
result := i8max + 1
expected := int8(-128)
if result != expected {
t.Errorf("Max int8 + 1: got %d, want %d (should wrap to -128)", result, expected)
}
})
t.Run("uint32 to float to int32 example", func(t *testing.T) {
var bigUint32 uint32 = 0xFFFFFFFF
result := int32(float64(bigUint32))
// This conversion has undefined behavior in Go
t.Logf("uint32 max -> float64 -> int32: %d (undefined behavior)", result)
})
t.Run("untyped constant with typed variable", func(t *testing.T) {
const untypedInt = 42
var i32 int32 = 70000
result := untypedInt + i32
expected := int32(70042)
if result != expected {
t.Errorf("untypedInt + i32: got %d (type %T), want %d (type int32)", result, result, expected)
}
})
t.Run("int8 arithmetic edge cases", func(t *testing.T) {
var a int8 = 100
var b int8 = 50
result := a + b
expected := int8(-106)
if result != expected {
t.Errorf("int8(100) + int8(50): got %d, want %d", result, expected)
}
})
t.Run("int8 multiplication overflow", func(t *testing.T) {
var m int8 = 64
result := m * 2
expected := int8(-128)
if result != expected {
t.Errorf("int8(64) * 2: got %d, want %d", result, expected)
}
})
t.Run("signed to unsigned conversion", func(t *testing.T) {
var negInt int32 = -1
result := uint32(negInt)
expected := uint32(0xFFFFFFFF)
if result != expected {
t.Errorf("uint32(int32(-1)): got 0x%X, want 0x%X", result, expected)
}
})
t.Run("unsigned to signed conversion", func(t *testing.T) {
var bigUint uint32 = 0xFFFFFFFF
result := int32(bigUint)
expected := int32(-1)
if result != expected {
t.Errorf("int32(uint32(0xFFFFFFFF)): got %d, want %d", result, expected)
}
})
t.Run("sign extension", func(t *testing.T) {
var i8 int8 = -1
result := int32(i8)
expected := int32(-1)
if result != expected {
t.Errorf("int32(int8(-1)): got %d, want %d (sign extension)", result, expected)
}
})
t.Run("truncation", func(t *testing.T) {
var i64 int64 = 0x123456789ABC
result := int32(i64)
expected := int32(0x56789ABC)
if result != expected {
t.Errorf("int32(int64(0x123456789ABC)): got 0x%X, want 0x%X (truncation)", uint32(result), uint32(expected))
}
})
}

View File

@@ -1,179 +0,0 @@
package gotest
import "testing"
// TestUntypedConstantWithTypedVariable tests untyped constants in operations with typed variables
// Issue #961: Program crashes when using untyped constants with typed variables
func TestUntypedConstantWithTypedVariable(t *testing.T) {
const untypedInt = 42
const untypedFloat = 3.14
const untypedComplex = 1 + 2i
// Test with int32
var i32 int32 = 70000
result := untypedInt + i32
expected := int32(70042)
if result != expected {
t.Errorf("untypedInt(42) + int32(70000) = %d (type %T), want %d (type int32)", result, result, expected)
}
// Test with int16 (no overflow)
var i16 int16 = 100
result16 := untypedInt + i16
expected16 := int16(142)
if result16 != expected16 {
t.Errorf("untypedInt(42) + int16(100) = %d (type %T), want %d (type int16)", result16, result16, expected16)
}
// Test with float32
var f32 float32 = 3.14159
resultF32 := untypedFloat + f32
expectedF32 := float32(6.28159)
if resultF32 < expectedF32-0.00001 || resultF32 > expectedF32+0.00001 {
t.Errorf("untypedFloat(3.14) + float32(3.14159) = %f (type %T), want ~%f (type float32)", resultF32, resultF32, expectedF32)
}
// Test with complex64
var c64 complex64 = 1 + 2i
resultC64 := untypedComplex + c64
expectedC64 := complex64(2 + 4i)
if resultC64 != expectedC64 {
t.Errorf("untypedComplex(1+2i) + complex64(1+2i) = %v (type %T), want %v (type complex64)", resultC64, resultC64, expectedC64)
}
}
// TestUntypedConstantArithmetic tests arithmetic with untyped constants
func TestUntypedConstantArithmetic(t *testing.T) {
const a = 100
const b = 200
// Basic operations
if c := a + b; c != 300 {
t.Errorf("100 + 200 = %d, want 300", c)
}
if d := a * b; d != 20000 {
t.Errorf("100 * 200 = %d, want 20000", d)
}
if e := b / a; e != 2 {
t.Errorf("200 / 100 = %d, want 2", e)
}
if f := b % a; f != 0 {
t.Errorf("200 %% 100 = %d, want 0", f)
}
}
// TestUntypedConstantExpression tests complex constant expressions
func TestUntypedConstantExpression(t *testing.T) {
const c1 = 1 << 10
const c2 = c1 * 1024
const c3 = c2 / 3
if c1 != 1024 {
t.Errorf("1 << 10 = %d, want 1024", c1)
}
if c2 != 1048576 {
t.Errorf("(1 << 10) * 1024 = %d, want 1048576", c2)
}
if c3 != 349525 {
t.Errorf("c2 / 3 = %d, want 349525", c3)
}
}
// TestMixedUntypedTypedExpressions tests expressions mixing untyped and typed
func TestMixedUntypedTypedExpressions(t *testing.T) {
const uConst = 10
var v1 int8 = 5
var v2 int16 = 10
var v3 int32 = 20
// These should take the type of the typed variable
result1 := uConst + v1
if _, ok := interface{}(result1).(int8); !ok {
t.Errorf("const(10) + int8(5) should be int8, got %T", result1)
}
if result1 != 15 {
t.Errorf("const(10) + int8(5) = %d, want 15", result1)
}
result2 := uConst + v2
if _, ok := interface{}(result2).(int16); !ok {
t.Errorf("const(10) + int16(10) should be int16, got %T", result2)
}
if result2 != 20 {
t.Errorf("const(10) + int16(10) = %d, want 20", result2)
}
result3 := uConst + v3
if _, ok := interface{}(result3).(int32); !ok {
t.Errorf("const(10) + int32(20) should be int32, got %T", result3)
}
if result3 != 30 {
t.Errorf("const(10) + int32(20) = %d, want 30", result3)
}
}
// TestUntypedBool tests untyped boolean constants
func TestUntypedBool(t *testing.T) {
const untypedTrue = true
const untypedFalse = false
var b1 bool = untypedTrue
var b2 bool = untypedFalse
if !b1 {
t.Error("untypedTrue should be true")
}
if b2 {
t.Error("untypedFalse should be false")
}
}
// TestUntypedString tests untyped string constants
func TestUntypedString(t *testing.T) {
const untypedString = "hello"
var s1 string = untypedString
if s1 != "hello" {
t.Errorf("untypedString = %q, want %q", s1, "hello")
}
}
// TestUntypedRune tests untyped rune constants
func TestUntypedRune(t *testing.T) {
const untypedRune = 'A'
var r1 rune = untypedRune
var r2 int32 = untypedRune
if r1 != 'A' {
t.Errorf("untypedRune as rune = %c, want 'A'", r1)
}
if r2 != 'A' {
t.Errorf("untypedRune as int32 = %d, want %d", r2, int32('A'))
}
if r1 != r2 {
t.Errorf("rune and int32 should be the same: %d != %d", r1, r2)
}
}
// TestUntypedZeroValues tests untyped zero constants
func TestUntypedZeroValues(t *testing.T) {
const zero = 0
const zeroFloat = 0.0
const emptyString = ""
var iz int32 = zero
var fz float64 = zeroFloat
var sz string = emptyString
if iz != 0 {
t.Errorf("untyped 0 -> int32 = %d, want 0", iz)
}
if fz != 0.0 {
t.Errorf("untyped 0.0 -> float64 = %f, want 0.0", fz)
}
if sz != "" {
t.Errorf("untyped \"\" -> string = %q, want \"\"", sz)
}
}