gno icon indicating copy to clipboard operation
gno copied to clipboard

Deviation in type checking from the standard Golang

Open Kouteki opened this issue 3 months ago • 5 comments

Severity: Informational

Description

In mempackage_type:gnovm/pkg/gnolang/types.go:1650–1704, the FindEmbeddedFieldType function is responsible for resolving fields and methods within a given data type. In line 1684, if a method is not found directly on the input type, the function continues the search in its base type.

This behavior deviates from the Go language specification. In standard Go, declared types do not automatically inherit methods from their underlying types. A method is only considered part of a declared type if it is explicitly defined with that type as its receiver. Allowing implicit method inheritance from base types introduces non-standard behavior and may lead to unexpected results or incorrect assumptions in contract logic.

Recommendation

We recommend aligning the method resolution logic with the standard Go specification by restricting method lookup to those explicitly defined on the declared type. If this deviation is intentional for Gno, it should be clearly documented to avoid confusion for developers expecting Go-compliant behavior.

Kouteki avatar Sep 19 '25 09:09 Kouteki

Hello 👋

I ran some tests to verify the behavior described in the report.

1. Declared types do not inherit methods from their underlying types

Both Go and Gno already behave correctly here:

type Base struct{}
func (Base) Foo() {}

type Derived Base

func ShouldNotWork() {
    var d Derived
    d.Foo() // correctly rejected in both Go and Gno
}

So Gno does not incorrectly promote methods from underlying types.

invalid gno package; type check errors:
            ┃   │ gno.land/r/demo/issue4789/issue4789.gno:15:4: d.Foo undefined (type Derived has no field or method Foo)

2. Why Gno searches through Base

Gno needs to walk through the underlying type when resolving embedded fields, because declared types whose underlying type is a struct inherit its structural layout, including embedded fields.

Example that should work (and does work in both Go and Gno):

type B struct{}
func (B) Foo() {}

type A struct{ B } // embeds B
type T A          // T retains the struct layout of A
type S struct{ T }

func main() {
    var s S
    s.Foo() // valid in both Go and Gno
}

Here Foo is promoted through the embedding: S → T → underlying A → embedded B → Foo

3. Possible patch

If any change is desired, the potential change would be to only recurse into Base when the underlying type can actually contain embedded fields , when the underlying type eventually resolves to:

  • a struct, or
  • an interface (embedded interfaces promote methods too)

4. Conclusion

From what I’ve tested, Gno’s current behavior matches Go for both:

  • declared type method
  • method promotion through embedded fields.

So I don’t believe a change is needed, but in case the core team want to change the code i would be happy to help or contribute on a patch.

MikaelVallenet avatar Nov 19 '25 11:11 MikaelVallenet

@thehowl @ltzmaxwell what do you think about the possible patch?

Kouteki avatar Nov 24 '25 11:11 Kouteki

I also pinged @jaekwon on TG for feedback

Kouteki avatar Dec 05 '25 19:12 Kouteki

It appears to be a false alarm. Thank @MikaelVallenet for the comment and the code — they already convey the intended idea. There’s potential to reduce the cost of the recursion as noted in both the comment above by @MikaelVallenet and the in original code comment. We can address that later anyway.

also will appreciate that if this kind of report can include an example for verification — a single filetest would be enough. thank you. cc: / @Kouteki

the simple way to add a new filetest: put the file like method38.gno in gnovm/tests/files, and run :

go test pkg/gnolang/files_test.go -test.short -update-golden-tests -run 'TestFiles$/method38.gno' -v -p 1 -timeout=30m

from xxx/gno/gnovm/ directory.

ltzmaxwell avatar Dec 09 '25 11:12 ltzmaxwell

i'll open a PR that add a test file and link to my comment to close this issue

MikaelVallenet avatar Dec 10 '25 10:12 MikaelVallenet