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.
This commit is contained in:
@@ -238,9 +238,6 @@ func namedOf(val *itype, path, name string, opts ...itypeOption) *itype {
|
||||
if path != "" {
|
||||
str = path + "." + name
|
||||
}
|
||||
for val.cat == aliasT {
|
||||
val = val.val
|
||||
}
|
||||
t := &itype{cat: aliasT, val: val, path: path, name: name, str: str}
|
||||
for _, opt := range opts {
|
||||
opt(t)
|
||||
@@ -1125,6 +1122,24 @@ func (t *itype) concrete() *itype {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *itype) underlying() *itype {
|
||||
if t.cat == aliasT {
|
||||
return t.val.underlying()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// typeDefined returns true if type t1 is defined from type t2 or t2 from t1.
|
||||
func typeDefined(t1, t2 *itype) bool {
|
||||
if t1.cat == aliasT && t1.val == t2 {
|
||||
return true
|
||||
}
|
||||
if t2.cat == aliasT && t2.val == t1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVariadic returns true if the function type is variadic.
|
||||
// If the type is not a function or is not variadic, it will
|
||||
// return false.
|
||||
@@ -1198,8 +1213,7 @@ func (t *itype) assignableTo(o *itype) bool {
|
||||
if t.equals(o) {
|
||||
return true
|
||||
}
|
||||
if t.cat == aliasT && o.cat == aliasT && t.val.id() != o.val.id() {
|
||||
// If alias types are not identical, it is not assignable.
|
||||
if t.cat == aliasT && o.cat == aliasT && (t.underlying().id() != o.underlying().id() || !typeDefined(t, o)) {
|
||||
return false
|
||||
}
|
||||
if t.isNil() && o.hasNil() || o.isNil() && t.hasNil() {
|
||||
|
||||
Reference in New Issue
Block a user