Skip to content

Commit 8b47705

Browse files
authored
Merge pull request #22178 from jketema/jketema/go-recv
Go: Track whether a type parameter type was declared as part of a receiver
2 parents 42843f1 + 09da46d commit 8b47705

17 files changed

Lines changed: 2392 additions & 67 deletions

File tree

go/downgrades/5ff5325d274ae4f86defa195577bc7c1370b72fa/go.dbscheme

Lines changed: 563 additions & 0 deletions
Large diffs are not rendered by default.

go/downgrades/5ff5325d274ae4f86defa195577bc7c1370b72fa/old.dbscheme

Lines changed: 563 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class TypeParamType extends @typeparamtype {
2+
string toString() { none() }
3+
}
4+
5+
class CompositeType extends @compositetype {
6+
string toString() { none() }
7+
}
8+
9+
class TypeParamParentObject extends @typeparamparentobject {
10+
string toString() { none() }
11+
}
12+
13+
from
14+
TypeParamType tp, string name, CompositeType bound, TypeParamParentObject parent, int idx,
15+
boolean is_from_recv
16+
where typeparam(tp, name, bound, parent, idx, is_from_recv)
17+
select tp, name, bound, parent, idx
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
description: Track whether a type parameter is from a receiver
2+
compatibility: partial
3+
typeparam.rel: run typeparam.qlo

go/extractor/dbscheme/dbscheme.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ func FloatColumn(columnName string) Column {
277277
return Column{columnName, FLOAT, false, true}
278278
}
279279

280+
// BooleanColumn constructs a column with name `columnName` holding boolean values
281+
func BooleanColumn(columnName string) Column {
282+
return Column{columnName, BOOLEAN, false, true}
283+
}
284+
280285
// A Table represents a database table
281286
type Table struct {
282287
name string

go/extractor/dbscheme/tables.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1241,4 +1241,5 @@ var TypeParamTable = NewTable("typeparam",
12411241
EntityColumn(CompositeType, "bound"),
12421242
EntityColumn(TypeParamParentObjectType, "parent"),
12431243
IntColumn("idx"),
1244-
).KeySet("parent", "idx")
1244+
BooleanColumn("is_from_recv"),
1245+
).KeySet("parent", "idx", "is_from_recv")

go/extractor/extractor.go

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ import (
3232
)
3333

3434
var MaxGoRoutines int
35-
var typeParamParent map[*types.TypeParam]types.Object = make(map[*types.TypeParam]types.Object)
35+
36+
type typeParamParentEntry struct {
37+
parent types.Object
38+
isFromReceiver bool
39+
}
40+
41+
var typeParamParent map[*types.TypeParam]typeParamParentEntry = make(map[*types.TypeParam]typeParamParentEntry)
3642

3743
func init() {
3844
// this sets the number of threads that the Go runtime will spawn; this is separate
@@ -530,8 +536,7 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label)
530536
// do not appear as objects in any scope, so they have to be dealt
531537
// with separately in extractMethods.
532538
if funcObj, ok := obj.(*types.Func); ok {
533-
populateTypeParamParents(funcObj.Type().(*types.Signature).TypeParams(), obj)
534-
populateTypeParamParents(funcObj.Type().(*types.Signature).RecvTypeParams(), obj)
539+
populateTypeParamParentsFromFunction(funcObj)
535540
}
536541
// Populate type parameter parents for defined types and alias types.
537542
if typeNameObj, ok := obj.(*types.TypeName); ok {
@@ -542,9 +547,9 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label)
542547
// careful with alias types because before Go 1.24 they would
543548
// return the underlying type.
544549
if tp, ok := typeNameObj.Type().(*types.Named); ok && !typeNameObj.IsAlias() {
545-
populateTypeParamParents(tp.TypeParams(), obj)
550+
populateTypeParamParents(tp.TypeParams(), obj, false)
546551
} else if tp, ok := typeNameObj.Type().(*types.Alias); ok {
547-
populateTypeParamParents(tp.TypeParams(), obj)
552+
populateTypeParamParents(tp.TypeParams(), obj, false)
548553
}
549554
}
550555
extractObject(tw, obj, lbl)
@@ -570,8 +575,7 @@ func extractMethod(tw *trap.Writer, meth *types.Func) trap.Label {
570575
if !exists {
571576
// Populate type parameter parents for methods. They do not appear as
572577
// objects in any scope, so they have to be dealt with separately here.
573-
populateTypeParamParents(meth.Type().(*types.Signature).TypeParams(), meth)
574-
populateTypeParamParents(meth.Type().(*types.Signature).RecvTypeParams(), meth)
578+
populateTypeParamParentsFromFunction(meth)
575579
extractObject(tw, meth, methlbl)
576580
}
577581

@@ -1677,9 +1681,9 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label {
16771681
}
16781682
case *types.TypeParam:
16791683
kind = dbscheme.TypeParamType.Index()
1680-
parentlbl := getTypeParamParentLabel(tw, tp)
1684+
parentlbl, isReceiverChild := getTypeParamParentLabel(tw, tp)
16811685
constraintLabel := extractType(tw, tp.Constraint())
1682-
dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, tp.Index())
1686+
dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, tp.Index(), isReceiverChild)
16831687
case *types.Union:
16841688
kind = dbscheme.TypeSetLiteral.Index()
16851689
for i := 0; i < tp.Len(); i++ {
@@ -1819,9 +1823,9 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) {
18191823
}
18201824
lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};definedtype", entitylbl))
18211825
case *types.TypeParam:
1822-
parentlbl := getTypeParamParentLabel(tw, tp)
1826+
parentlbl, isReceiverChild := getTypeParamParentLabel(tw, tp)
18231827
idx := tp.Index()
1824-
lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%v},%d,%s;typeparamtype", parentlbl, idx, tp.Obj().Name()))
1828+
lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%v},%d,%t,%s;typeparamtype", parentlbl, idx, isReceiverChild, tp.Obj().Name()))
18251829
case *types.Union:
18261830
var b strings.Builder
18271831
for i := 0; i < tp.Len(); i++ {
@@ -2005,11 +2009,18 @@ func extractTypeParamDecls(tw *trap.Writer, fields *ast.FieldList, parent trap.L
20052009
}
20062010
}
20072011

2012+
func populateTypeParamParentsFromFunction(funcObj *types.Func) {
2013+
signature := funcObj.Type().(*types.Signature)
2014+
populateTypeParamParents(signature.RecvTypeParams(), funcObj, true)
2015+
populateTypeParamParents(signature.TypeParams(), funcObj, false)
2016+
}
2017+
20082018
// populateTypeParamParents sets `parent` as the parent of the elements of `typeparams`
2009-
func populateTypeParamParents(typeparams *types.TypeParamList, parent types.Object) {
2019+
// and records whether elements are defined in a receiver.
2020+
func populateTypeParamParents(typeparams *types.TypeParamList, parent types.Object, isFromReceiver bool) {
20102021
if typeparams != nil {
2011-
for idx := 0; idx < typeparams.Len(); idx++ {
2012-
setTypeParamParent(typeparams.At(idx), parent)
2022+
for tparam := range typeparams.TypeParams() {
2023+
setTypeParamParent(tparam, parent, isFromReceiver)
20132024
}
20142025
}
20152026
}
@@ -2028,24 +2039,26 @@ func getObjectBeingUsed(tw *trap.Writer, ident *ast.Ident) types.Object {
20282039
}
20292040
}
20302041

2031-
func getTypeParamParentLabel(tw *trap.Writer, tp *types.TypeParam) trap.Label {
2032-
parent, exists := typeParamParent[tp]
2042+
func getTypeParamParentLabel(tw *trap.Writer, tp *types.TypeParam) (trap.Label, bool) {
2043+
entry, exists := typeParamParent[tp]
20332044
if !exists {
20342045
log.Fatalf("Parent of type parameter does not exist: %s %s", tp.String(), tp.Constraint().String())
20352046
}
2036-
parentlbl, _ := tw.Labeler.ScopedObjectID(parent, func() trap.Label {
2047+
parentlbl, _ := tw.Labeler.ScopedObjectID(entry.parent, func() trap.Label {
20372048
log.Fatalf("getTypeLabel() called for parent of type parameter %s", tp.String())
20382049
return trap.InvalidLabel
20392050
})
2040-
return parentlbl
2051+
return parentlbl, entry.isFromReceiver
20412052
}
20422053

2043-
func setTypeParamParent(tp *types.TypeParam, newobj types.Object) {
2044-
obj, exists := typeParamParent[tp]
2054+
func setTypeParamParent(tp *types.TypeParam, parent types.Object, isFromReceiver bool) {
2055+
entry, exists := typeParamParent[tp]
2056+
newEntry := typeParamParentEntry{parent, isFromReceiver}
20452057
if !exists {
2046-
typeParamParent[tp] = newobj
2047-
} else if newobj != obj {
2048-
log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), obj, newobj)
2058+
typeParamParent[tp] = newEntry
2059+
} else if entry != newEntry {
2060+
log.Fatalf("Parent of type parameter '%s %s' being set to a different value: {'%s', %t}' vs {'%s', %t}",
2061+
tp.String(), tp.Constraint().String(), entry.parent, entry.isFromReceiver, parent, isFromReceiver)
20492062
}
20502063
}
20512064

go/extractor/trap/trapwriter.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ func (tw *Writer) Emit(table string, values []interface{}) error {
165165
fmt.Fprintf(tw.wzip, "%d", value)
166166
case float64:
167167
fmt.Fprintf(tw.wzip, "%e", value)
168+
case bool:
169+
fmt.Fprintf(tw.wzip, "%t", value)
168170
default:
169171
return errors.New("Cannot emit value")
170172
}

go/ql/lib/go.dbscheme

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,9 @@ has_ellipsis(int id: @callorconversionexpr ref);
244244

245245
variadic(int id: @signaturetype ref);
246246

247-
#keyset[parent, idx]
248-
typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @compositetype ref,
249-
int parent: @typeparamparentobject ref, int idx: int ref);
247+
#keyset[parent, idx, is_from_recv]
248+
typeparam(unique int tp: @typeparamtype ref, string name: string ref,
249+
int bound: @compositetype ref, int parent: @typeparamparentobject ref, int idx: int ref, boolean is_from_recv: boolean ref);
250250

251251
@container = @file | @folder;
252252

go/ql/lib/go.dbscheme.stats

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17791,6 +17791,10 @@
1779117791
<k>idx</k>
1779217792
<v>3126</v>
1779317793
</e>
17794+
<e>
17795+
<k>is_from_recv</k>
17796+
<v>0</v>
17797+
</e>
1779417798
</columnsizes>
1779517799
<dependencies>
1779617800
<dep>

0 commit comments

Comments
 (0)