Skip to content

Commit

Permalink
fix(go_indexer): fix satisfies check for 1.18beta2 (#5235)
Browse files Browse the repository at this point in the history
  • Loading branch information
schroederc committed Mar 4, 2022
1 parent e57ba0a commit 60bd2fa
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 11 deletions.
2 changes: 1 addition & 1 deletion external.bzl
Expand Up @@ -34,7 +34,7 @@ load("//kythe/rust/cargo:crates.bzl", "raze_fetch_remote_crates")

def _rule_dependencies():
go_rules_dependencies()
go_register_toolchains(version = "1.18beta1")
go_register_toolchains(version = "1.18beta2")
gazelle_dependencies()
rules_java_dependencies()
rules_proto_dependencies()
Expand Down
61 changes: 51 additions & 10 deletions kythe/go/indexer/emit.go
Expand Up @@ -857,6 +857,9 @@ func (e *emitter) emitSatisfactions() {
}
}

// Shared Context across all generic assignability checks.
tctx := types.NewContext()

// Cache the method set of each named type in this package.
var msets typeutil.MethodSetCache
// Cache the overrides we've noticed to avoid duplicate entries.
Expand Down Expand Up @@ -893,30 +896,24 @@ func (e *emitter) emitSatisfactions() {
case ifx && ify && ymset.Len() > 0:
// x and y are both interfaces. Note that extension is handled
// elsewhere as part of the type spec for the interface.
if types.AssignableTo(x, y) {
if assignableTo(tctx, x, y) {
e.writeSatisfies(xobj, yobj)
}
if types.AssignableTo(y, x) {
if assignableTo(tctx, y, x) {
e.writeSatisfies(yobj, xobj)
}

case ifx:
// y is a concrete type
pymset := msets.MethodSet(types.NewPointer(y))
if types.AssignableTo(y, x) {
e.writeSatisfies(yobj, xobj)
e.emitOverrides(ymset, pymset, xmset, cache)
} else if py := types.NewPointer(y); types.AssignableTo(py, x) {
if assignableTo(tctx, y, x) {
e.writeSatisfies(yobj, xobj)
e.emitOverrides(ymset, pymset, xmset, cache)
}

case ify && ymset.Len() > 0:
// x is a concrete type
if types.AssignableTo(x, y) {
e.writeSatisfies(xobj, yobj)
e.emitOverrides(xmset, pxmset, ymset, cache)
} else if px := types.NewPointer(x); types.AssignableTo(px, y) {
if assignableTo(tctx, x, y) {
e.writeSatisfies(xobj, yobj)
e.emitOverrides(xmset, pxmset, ymset, cache)
}
Expand Down Expand Up @@ -1351,3 +1348,47 @@ func firstNonEmptyComment(cs ...*ast.CommentGroup) *ast.CommentGroup {
}
return nil
}

func canBeAssignableTo(v, t types.Type) bool {
return types.AssignableTo(v, t) || types.AssignableTo(types.NewPointer(v), t)
}

func assignableTo(tctx *types.Context, V, T types.Type) bool {
// If V and T are not both named, or do not have matching non-empty type
// parameter lists, fall back on types.AssignableTo.
VN, Vnamed := V.(*types.Named)
TN, Tnamed := T.(*types.Named)
if !Vnamed || !Tnamed {
return canBeAssignableTo(V, T)
}

vtparams := VN.TypeParams()
ttparams := TN.TypeParams()
if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 {
return canBeAssignableTo(V, T)
}

// V and T have the same (non-zero) number of type params. Instantiate both
// with the type parameters of V. This must always succeed for V, and will
// succeed for T if and only if the type set of each type parameter of V is a
// subset of the type set of the corresponding type parameter of T, meaning
// that every instantiation of V corresponds to a valid instantiation of T.

targs := make([]types.Type, vtparams.Len())
for i := 0; i < vtparams.Len(); i++ {
targs[i] = vtparams.At(i)
}

vinst, err := types.Instantiate(tctx, V, targs, true)
if err != nil {
log.Printf("ERROR: type parameters should satisfy their own constraints: %v", err)
return false
}

tinst, err := types.Instantiate(tctx, T, targs, true)
if err != nil {
return false
}

return canBeAssignableTo(vinst, tinst)
}

0 comments on commit 60bd2fa

Please sign in to comment.