@@ -42,6 +42,7 @@ type gobCallee struct {
42
42
ValidForCallStmt bool // function body is "return expr" where expr is f() or <-ch
43
43
NumResults int // number of results (according to type, not ast.FieldList)
44
44
Params []* paramInfo // information about parameters (incl. receiver)
45
+ TypeParams []* paramInfo // information about type parameters
45
46
Results []* paramInfo // information about result variables
46
47
Effects []int // order in which parameters are evaluated (see calleefx)
47
48
HasDefer bool // uses defer
@@ -113,17 +114,6 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
113
114
return nil , fmt .Errorf ("cannot inline function %s as it has no body" , name )
114
115
}
115
116
116
- // TODO(adonovan): support inlining of instantiated generic
117
- // functions by replacing each occurrence of a type parameter
118
- // T by its instantiating type argument (e.g. int). We'll need
119
- // to wrap the instantiating type in parens when it's not an
120
- // ident or qualified ident to prevent "if x == struct{}"
121
- // parsing ambiguity, or "T(x)" where T = "*int" or "func()"
122
- // from misparsing.
123
- if funcHasTypeParams (decl ) {
124
- return nil , fmt .Errorf ("cannot inline generic function %s: type parameters are not yet supported" , name )
125
- }
126
-
127
117
// Record the location of all free references in the FuncDecl.
128
118
// (Parameters are not free by this definition.)
129
119
var (
@@ -347,6 +337,7 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
347
337
}
348
338
349
339
params , results , effects , falcon := analyzeParams (logf , fset , info , decl )
340
+ tparams := analyzeTypeParams (logf , fset , info , decl )
350
341
return & Callee {gobCallee {
351
342
Content : content ,
352
343
PkgPath : pkg .Path (),
@@ -357,6 +348,7 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
357
348
ValidForCallStmt : validForCallStmt ,
358
349
NumResults : sig .Results ().Len (),
359
350
Params : params ,
351
+ TypeParams : tparams ,
360
352
Results : results ,
361
353
Effects : effects ,
362
354
HasDefer : hasDefer ,
@@ -404,20 +396,15 @@ type refInfo struct {
404
396
IsSelectionOperand bool
405
397
}
406
398
407
- // analyzeParams computes information about parameters of function fn ,
399
+ // analyzeParams computes information about parameters of the function declared by decl ,
408
400
// including a simple "address taken" escape analysis.
409
401
//
410
402
// It returns two new arrays, one of the receiver and parameters, and
411
- // the other of the result variables of function fn .
403
+ // the other of the result variables of the function .
412
404
//
413
405
// The input must be well-typed.
414
406
func analyzeParams (logf func (string , ... any ), fset * token.FileSet , info * types.Info , decl * ast.FuncDecl ) (params , results []* paramInfo , effects []int , _ falconResult ) {
415
- fnobj , ok := info .Defs [decl .Name ]
416
- if ! ok {
417
- panic (fmt .Sprintf ("%s: no func object for %q" ,
418
- fset .PositionFor (decl .Name .Pos (), false ), decl .Name )) // ill-typed?
419
- }
420
- sig := fnobj .Type ().(* types.Signature )
407
+ sig := signature (fset , info , decl )
421
408
422
409
paramInfos := make (map [* types.Var ]* paramInfo )
423
410
{
@@ -504,6 +491,52 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
504
491
return params , results , effects , falcon
505
492
}
506
493
494
+ // analyzeTypeParams computes information about the type parameters of the function declared by decl.
495
+ func analyzeTypeParams (_ logger , fset * token.FileSet , info * types.Info , decl * ast.FuncDecl ) []* paramInfo {
496
+ sig := signature (fset , info , decl )
497
+ paramInfos := make (map [* types.TypeName ]* paramInfo )
498
+ var params []* paramInfo
499
+ collect := func (tpl * types.TypeParamList ) {
500
+ for i := range tpl .Len () {
501
+ typeName := tpl .At (i ).Obj ()
502
+ info := & paramInfo {Name : typeName .Name ()}
503
+ params = append (params , info )
504
+ paramInfos [typeName ] = info
505
+ }
506
+ }
507
+ collect (sig .RecvTypeParams ())
508
+ collect (sig .TypeParams ())
509
+
510
+ // Find references.
511
+ // We don't care about most of the properties that matter for parameter references:
512
+ // a type is immutable, cannot have its address taken, and does not undergo conversions.
513
+ // TODO(jba): can we nevertheless combine this with the traversal in analyzeParams?
514
+ var stack []ast.Node
515
+ stack = append (stack , decl .Type ) // for scope of function itself
516
+ astutil .PreorderStack (decl .Body , stack , func (n ast.Node , stack []ast.Node ) bool {
517
+ if id , ok := n .(* ast.Ident ); ok {
518
+ if v , ok := info .Uses [id ].(* types.TypeName ); ok {
519
+ if pinfo , ok := paramInfos [v ]; ok {
520
+ ref := refInfo {Offset : int (n .Pos () - decl .Pos ())}
521
+ pinfo .Refs = append (pinfo .Refs , ref )
522
+ pinfo .Shadow = pinfo .Shadow .add (info , nil , pinfo .Name , stack )
523
+ }
524
+ }
525
+ }
526
+ return true
527
+ })
528
+ return params
529
+ }
530
+
531
+ func signature (fset * token.FileSet , info * types.Info , decl * ast.FuncDecl ) * types.Signature {
532
+ fnobj , ok := info .Defs [decl .Name ]
533
+ if ! ok {
534
+ panic (fmt .Sprintf ("%s: no func object for %q" ,
535
+ fset .PositionFor (decl .Name .Pos (), false ), decl .Name )) // ill-typed?
536
+ }
537
+ return fnobj .Type ().(* types.Signature )
538
+ }
539
+
507
540
// -- callee helpers --
508
541
509
542
// analyzeAssignment looks at the the given stack, and analyzes certain
0 commit comments