diff --git a/kythe/go/indexer/emit.go b/kythe/go/indexer/emit.go index 5b764d945e..cf147df2bf 100644 --- a/kythe/go/indexer/emit.go +++ b/kythe/go/indexer/emit.go @@ -168,6 +168,10 @@ func (pi *PackageInfo) Emit(ctx context.Context, sink Sink, opts *EmitOptions) e e.visitRangeStmt(n, stack) case *ast.CompositeLit: e.visitCompositeLit(n, stack) + case *ast.IndexExpr: + e.visitIndexExpr(n, stack) + case *ast.IndexListExpr: + e.visitIndexListExpr(n, stack) } return true }), file) @@ -223,7 +227,14 @@ func (e *emitter) visitIdent(id *ast.Ident, stack stackFunc) { return } - target := e.pi.ObjectVName(obj) + var target *spb.VName + if n, ok := obj.(*types.TypeName); ok && obj.Pkg() == nil { + // Handle type arguments in instantiated types. + target = e.emitType(n.Type()) + } else { + target = e.pi.ObjectVName(obj) + } + if target == nil { // This should not happen in well-formed packages, but can if the // extractor gets confused. Avoid emitting confusing references in such @@ -293,7 +304,7 @@ func (e *emitter) visitFuncDecl(decl *ast.FuncDecl, stack stackFunc) { // with given constructor and parameters. The constructor's kind is also // emitted if this is the first time seeing it. func (e *emitter) emitTApp(ms *cpb.MarkedSource, ctorKind string, ctor *spb.VName, params ...*spb.VName) *spb.VName { - if e.pi.typeEmitted.Add(ctor.Signature) { + if ctorKind != "" && e.pi.typeEmitted.Add(ctor.Signature) { e.writeFact(ctor, facts.NodeKind, ctorKind) if ctorKind == nodes.TBuiltin { e.emitBuiltinMarkedSource(ctor) @@ -330,7 +341,18 @@ func (e *emitter) emitType(typ types.Type) *spb.VName { switch typ := typ.(type) { case *types.Named: - v = e.pi.ObjectVName(typ.Obj()) + if typ.TypeArgs().Len() == 0 { + v = e.pi.ObjectVName(typ.Obj()) + } else { + // Instantiated Named types produce tapps + ctor := e.emitType(typ.Origin()) + args := typ.TypeArgs() + var params []*spb.VName + for i := 0; i < args.Len(); i++ { + params = append(params, e.emitType(args.At(i))) + } + v = e.emitTApp(genericTAppMS, "", ctor, params...) + } case *types.Basic: v = govname.BasicType(typ) if e.pi.typeEmitted.Add(v.Signature) { @@ -694,6 +716,22 @@ func (e *emitter) visitCompositeLit(expr *ast.CompositeLit, stack stackFunc) { } } +// visitIndexExpr handles references to instantiated types with a single type +// parameter. +func (e *emitter) visitIndexExpr(expr *ast.IndexExpr, stack stackFunc) { + if n, ok := e.pi.Info.TypeOf(expr).(*types.Named); ok && n.TypeArgs().Len() > 0 { + e.writeRef(expr, e.emitType(n), edges.Ref) + } +} + +// visitIndexListExpr handles references to instantiated types with multiple +// type parameters. +func (e *emitter) visitIndexListExpr(expr *ast.IndexListExpr, stack stackFunc) { + if n, ok := e.pi.Info.TypeOf(expr).(*types.Named); ok && n.TypeArgs().Len() > 0 { + e.writeRef(expr, e.emitType(n), edges.Ref) + } +} + // emitPosRef emits an anchor spanning loc, pointing to obj. func (e *emitter) emitPosRef(loc ast.Node, obj types.Object, kind string) { target := e.pi.ObjectVName(obj) diff --git a/kythe/go/indexer/markedsource.go b/kythe/go/indexer/markedsource.go index 6eb0209abb..b36fe49464 100644 --- a/kythe/go/indexer/markedsource.go +++ b/kythe/go/indexer/markedsource.go @@ -334,6 +334,22 @@ var ( }}, PreText: "<-chan ", } + genericTAppMS = &cpb.MarkedSource{ + Kind: cpb.MarkedSource_TYPE, + Child: []*cpb.MarkedSource{{ + Kind: cpb.MarkedSource_LOOKUP_BY_PARAM, + LookupIndex: 0, + }, { + Kind: cpb.MarkedSource_BOX, + PreText: "[", + PostText: "]", + Child: []*cpb.MarkedSource{{ + Kind: cpb.MarkedSource_PARAMETER_LOOKUP_BY_PARAM, + LookupIndex: 1, + }}, + PostChildText: ", ", + }}, + } ) func arrayTAppMS(length int64) *cpb.MarkedSource { diff --git a/kythe/go/indexer/testdata/generics/genericmethod.go b/kythe/go/indexer/testdata/generics/genericmethod.go index 305db95ec0..59ee5464fb 100644 --- a/kythe/go/indexer/testdata/generics/genericmethod.go +++ b/kythe/go/indexer/testdata/generics/genericmethod.go @@ -1,7 +1,6 @@ package genericmethod func main() { - //- @Container ref Container c := &Container[string]{"element"} //- @Get ref Get c.Get() diff --git a/kythe/go/indexer/testdata/generics/genericstruct.go b/kythe/go/indexer/testdata/generics/genericstruct.go index 6288b2cd6d..efc9d6cdc2 100644 --- a/kythe/go/indexer/testdata/generics/genericstruct.go +++ b/kythe/go/indexer/testdata/generics/genericstruct.go @@ -1,5 +1,25 @@ package genericstruct +func main() { + //- @"Container[string]" ref ContainerApp + //- @Container ref Container + //- @string ref String + _ = &Container[string]{"element"} + //- ContainerApp.node/kind "tapp" + //- ContainerApp param.0 Container + //- ContainerApp param.1 String + + //- @"Pair[string, int]" ref PairApp + //- @Pair ref Pair + //- @string ref String + //- @int ref Int + _ = &Pair[string, int]{"first", 2} + //- PairApp.node/kind "tapp" + //- PairApp param.0 Pair + //- PairApp param.1 String + //- PairApp param.2 Int +} + //- @Container defines/binding Container //- Container.node/kind record //- @T defines/binding TVar @@ -11,13 +31,16 @@ type Container[T any] struct { } //- @T defines/binding TVar2 +//- @U defines/binding UVar //- !{@T defines/binding TVar} //- !{@T ref TVar} -type Container2[T any] struct { +type Pair[T any, U any] struct { //- @T ref TVar2 //- !{@T defines/binding TVar} //- !{@T ref TVar} - Element T + First T + //- @U ref UVar + Second U } // kythe/go/indexer/genericstruct_test.Container.T