Skip to content

Go: Update to 1.27#22042

Draft
jketema wants to merge 8 commits into
mainfrom
jketema/go-1.27
Draft

Go: Update to 1.27#22042
jketema wants to merge 8 commits into
mainfrom
jketema/go-1.27

Conversation

@jketema

@jketema jketema commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions github-actions Bot added the Go label Jun 24, 2026
@jketema jketema added the depends on internal PR This PR should only be merged in sync with an internal Semmle PR label Jun 24, 2026
@jketema jketema force-pushed the jketema/go-1.27 branch 3 times, most recently from f0842b5 to 91e1d28 Compare June 30, 2026 15:20

@owen-mc owen-mc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass review.

Comment thread go/extractor/extractor.go
Comment on lines +541 to +542
recvTypeParams := funcObj.Type().(*types.Signature).RecvTypeParams()
populateTypeParamParents(recvTypeParams, obj, typeParams.Len())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory these lines shouldn't be needed here, because the comment above says that methods do not appear as objects in any scope, so we should only be dealing with top-level functions. However, rather than deleting it, I think it would be better to create a separate function for these four lines, as they are duplicated lower down. Maybe populateTypeParamParentsFromFunction(funcObj *types.Func). (Can you tell I like long method names? 😆 )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to refactor. The only thing I changed here was the addition of the offset. I simply assumed that this code was necessary (because it was already there 😄 ).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 😆

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory these lines shouldn't be needed here

This only applies to RecvTypeParams, right? The TypeParams are needed for generic functions.

@jketema jketema Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also not clear to me how RecvTypeParams can ever be non-empty here. And somewhat similar: how TypeParams could ever have been non-empty for methods before Go 1.27.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

factored out in #22178

Comment thread go/extractor/extractor.go
for i := 0; i < origintp.NumMethods(); i++ {
meth := origintp.Method(i).Origin()

typeParams := tp.Method(i).Type().(*types.Signature).TypeParams()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that this line wants to use the instantiated receiver type (tp instead of origintp), and the instantiated method type (tp.Method(i).Type() rather than tp.Method(i).Type().Origin())? It seems odd to assign meth as the parent in the line below when meth is different from tp.Method(i). Do we even need to populate type param parents here, as we will do something very similar in extractMethods.

Perhaps we should put a short comment here, as it will no doubt be confusing to future readers as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, it needs to be tp, or at least that solves the Parent of type parameter does not exist: Q any error I was seeing. I'm absolutely not sure if meth is correct here. I think I need to better understand what relations are affected by populateTypeParamParents.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to provide some context first. The problem is coming from the select expression in

s2.GenericMethod2[string]("hello")

That is s2.GenericMethod2. Without the index ([string]) this still has a generic type func[P4 any](x P4). This type is separate from the generic type the declaration of GenericMethod2 has. We do not extract s2.GenericMethod2, but only its Origin. We, however, need the type parameters of the type of s2.GenericMethod2, when we assign a type to that expression.

I think this means there are two solutions here:

  1. Extract s2.GenericMethod2, which doesn't seem to be consistent with how the rest of the extractor handles generics.
  2. Map the type parameters from the type of s2.GenericMethod2 to the type parameters from declaration that occurs in the source code.

(2) we can do by constructing a separate map from type parameters to type parameters near the call sides of getTypeParamParentLabel. However, given what ends up in the database w.r.t. type parameters, this is effectively the same as what I do here by using meth in combination with the type parameters from the instantiated type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does ☝️ make sense?

Comment thread go/extractor/extractor.go
log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), obj, newobj)
typeParamParent[tp] = typeParamParentEntry{newobj, idx}
} else if entry.parent != newobj || entry.index != idx {
log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), entry.parent, newobj)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message is slightly inaccurate, as it only prints the objects but it could be printed if the objects are the same but the indexes are different. It's not a big thing, but consider printing the indexes as well (or the typeParamParentEntry struct.

Comment thread go/extractor/extractor.go
parentlbl, idx := getTypeParamParentLabel(tw, tp)
constraintLabel := extractType(tw, tp.Constraint())
dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, tp.Index())
dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, idx)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update the QLDoc for TypeParamType.getIndex() to be clear about what it means, especially as it is now different from what the go compiler libraries use. For a type param in a named type definition it is what it was before: the index in the type params for that named type. For a type param in a method definition it is now the index in the list of type params, where the type params on the method come first and the type params on the receiver come second. (Do we want this order? From left to right might make more sense.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to switch the order. I just kept things in the order in which the code appears for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say left-to-right order, so receiver type parameters first and then method type parameters, is slightly more intuitive.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to add a column to typeparam, or have a new table, that distinguishes type parameters from receiver type parameters. I'm happy to implement that if you think that would be better.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or split the receiver type parameters off in a completely separate table.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to add a column to typeparam,

I think this might be the best solution actually. Have an extra column is_from_recv or something.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done here: #22178

Comment thread go/ql/test/library-tests/semmle/go/Function/genericMethods.go Outdated
@jketema jketema force-pushed the jketema/go-1.27 branch 2 times, most recently from 4bb4bfc to 83870c8 Compare July 10, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

depends on internal PR This PR should only be merged in sync with an internal Semmle PR documentation Go

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants