diff options
author | Ayke van Laethem <[email protected]> | 2018-10-07 02:06:48 +0200 |
---|---|---|
committer | Ayke van Laethem <[email protected]> | 2018-10-07 02:06:48 +0200 |
commit | 4957db89f49dfd4aba6afbb8aa4846d54b26f614 (patch) | |
tree | a89b71c750d6232a5cb68d0552bc7a097cec3fbe /testdata | |
parent | 482c5633dd34af850d384a74559ed9d977417c7c (diff) | |
download | tinygo-4957db89f49dfd4aba6afbb8aa4846d54b26f614.tar.gz tinygo-4957db89f49dfd4aba6afbb8aa4846d54b26f614.zip |
compiler: fix interface calls for big underlying values
When the underlying value of an interface does not fit in a pointer, a
pointer to the value was correctly inserted in the heap. However, the
receiving method still assumed it got the underlying value instead of a
pointer to it leading to a crash.
This commit inserts wrapper functions for method calls on interfaces.
The bug wasn't obvious as on a 64-bit system, the underlying value was
almost always put directly in the interface. However, it led to a crash
on the AVR platform where pointer are (usually) just 16 bits making it
far more likely that underlying values cannot be directly stored in an
interface.
Diffstat (limited to 'testdata')
-rw-r--r-- | testdata/interface.go | 87 | ||||
-rw-r--r-- | testdata/interface.txt | 13 |
2 files changed, 100 insertions, 0 deletions
diff --git a/testdata/interface.go b/testdata/interface.go new file mode 100644 index 000000000..f24a995fa --- /dev/null +++ b/testdata/interface.go @@ -0,0 +1,87 @@ +package main + +func main() { + thing := &Thing{"foo"} + println("thing:", thing.String()) + thing.Print() + printItf(5) + printItf(byte('x')) + printItf("foo") + printItf(*thing) + printItf(thing) + printItf(Stringer(thing)) + printItf(Number(3)) + array := Array([4]uint32{1, 7, 11, 13}) + printItf(array) + s := Stringer(thing) + println("Stringer.String():", s.String()) + var itf interface{} = s + println("Stringer.(*Thing).String():", itf.(Stringer).String()) +} + +func printItf(val interface{}) { + switch val := val.(type) { + case Doubler: + println("is Doubler:", val.Double()) + case Tuple: + println("is Tuple:", val.Nth(0), val.Nth(1), val.Nth(2), val.Nth(3)) + val.Print() + case int: + println("is int:", val) + case byte: + println("is byte:", val) + case string: + println("is string:", val) + case Thing: + println("is Thing:", val.String()) + case *Thing: + println("is *Thing:", val.String()) + case Foo: + println("is Foo:", val) + default: + println("is ?") + } +} + +type Thing struct { + name string +} + +func (t Thing) String() string { + return t.name +} + +func (t Thing) Print() { + println("Thing.Print:", t.name) +} + +type Stringer interface { + String() string +} + +type Foo int + +type Number int + +func (n Number) Double() int { + return int(n) * 2 +} + +type Doubler interface { + Double() int +} + +type Tuple interface { + Nth(int) uint32 + Print() +} + +type Array [4]uint32 + +func (a Array) Nth(n int) uint32 { + return a[n] +} + +func (a Array) Print() { + println("Array len:", len(a)) +} diff --git a/testdata/interface.txt b/testdata/interface.txt new file mode 100644 index 000000000..f16dfbe00 --- /dev/null +++ b/testdata/interface.txt @@ -0,0 +1,13 @@ +thing: foo +Thing.Print: foo +is int: 5 +is byte: 120 +is string: foo +is Thing: foo +is *Thing: foo +is *Thing: foo +is Doubler: 6 +is Tuple: 1 7 11 13 +Array len: 4 +Stringer.String(): foo +Stringer.(*Thing).String(): foo |