Skip to content

Commit f76db27

Browse files
authored
interp: fix resolution of methods on aliased types
The type.val field was always pointing to the final underlying type for aliased types, defeating a possible match if a method was attached to a type in between. Now the complete chain of aliases is always preserved. We have added an underlying() itype method which returns the underlying type of a defined type (aliasT), even in the presence of multiple indirections. We have added a definedType function which checks if type t1 is defined from type t2 or t2 defined from t1, required when checking assignability of aliasT types. Fixes #1411. PS: this is the 2nd attempt, as the first version #1412 wasn't passing _test/issue-1408.go as well. This PR does pass and supersedes #1412.
1 parent 996b1e3 commit f76db27

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

_test/issue-1411.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
type Number int32
4+
5+
func (n Number) IsValid() bool { return true }
6+
7+
type Number1 = Number
8+
9+
type Number2 = Number1
10+
11+
func main() {
12+
a := Number2(5)
13+
println(a.IsValid())
14+
}
15+
16+
// Output: true

interp/cfg.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,11 +2700,7 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
27002700
}
27012701
case valueT:
27022702
if rtyp == nil {
2703-
rtyp = n.typ.rtype
2704-
}
2705-
// TODO(mpl): I do not understand where this side-effect is coming from, and why it happens. quickfix for now.
2706-
if rtyp == nil {
2707-
rtyp = n.typ.val.rtype
2703+
rtyp = n.typ.TypeOf()
27082704
}
27092705
switch k := rtyp.Kind(); k {
27102706
case reflect.Struct:

interp/type.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,6 @@ func namedOf(val *itype, path, name string, opts ...itypeOption) *itype {
238238
if path != "" {
239239
str = path + "." + name
240240
}
241-
for val.cat == aliasT {
242-
val = val.val
243-
}
244241
t := &itype{cat: aliasT, val: val, path: path, name: name, str: str}
245242
for _, opt := range opts {
246243
opt(t)
@@ -1125,6 +1122,24 @@ func (t *itype) concrete() *itype {
11251122
return t
11261123
}
11271124

1125+
func (t *itype) underlying() *itype {
1126+
if t.cat == aliasT {
1127+
return t.val.underlying()
1128+
}
1129+
return t
1130+
}
1131+
1132+
// typeDefined returns true if type t1 is defined from type t2 or t2 from t1.
1133+
func typeDefined(t1, t2 *itype) bool {
1134+
if t1.cat == aliasT && t1.val == t2 {
1135+
return true
1136+
}
1137+
if t2.cat == aliasT && t2.val == t1 {
1138+
return true
1139+
}
1140+
return false
1141+
}
1142+
11281143
// isVariadic returns true if the function type is variadic.
11291144
// If the type is not a function or is not variadic, it will
11301145
// return false.
@@ -1198,8 +1213,7 @@ func (t *itype) assignableTo(o *itype) bool {
11981213
if t.equals(o) {
11991214
return true
12001215
}
1201-
if t.cat == aliasT && o.cat == aliasT && t.val.id() != o.val.id() {
1202-
// If alias types are not identical, it is not assignable.
1216+
if t.cat == aliasT && o.cat == aliasT && (t.underlying().id() != o.underlying().id() || !typeDefined(t, o)) {
12031217
return false
12041218
}
12051219
if t.isNil() && o.hasNil() || o.isNil() && t.hasNil() {

0 commit comments

Comments
 (0)