src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

methods.go (5337B)


      1 // Copyright 2013 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package ssa
      6 
      7 // This file defines utilities for population of method sets.
      8 
      9 import (
     10 	"fmt"
     11 	"go/types"
     12 
     13 	"golang.org/x/tools/go/types/typeutil"
     14 	"golang.org/x/tools/internal/typesinternal"
     15 )
     16 
     17 // MethodValue returns the Function implementing method sel, building
     18 // wrapper methods on demand. It returns nil if sel denotes an
     19 // interface or generic method.
     20 //
     21 // Precondition: sel.Kind() == MethodVal.
     22 //
     23 // Thread-safe.
     24 //
     25 // Acquires prog.methodsMu.
     26 func (prog *Program) MethodValue(sel *types.Selection) *Function {
     27 	if sel.Kind() != types.MethodVal {
     28 		panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel))
     29 	}
     30 	T := sel.Recv()
     31 	if types.IsInterface(T) {
     32 		return nil // interface method or type parameter
     33 	}
     34 
     35 	if prog.isParameterized(T, sel.Type()) {
     36 		return nil // method on generic type or generic method
     37 	}
     38 
     39 	if prog.mode&LogSource != 0 {
     40 		defer logStack("MethodValue %s %v", T, sel)()
     41 	}
     42 
     43 	var b builder
     44 
     45 	m := func() *Function {
     46 		prog.methodsMu.Lock()
     47 		defer prog.methodsMu.Unlock()
     48 
     49 		// Get or create SSA method set.
     50 		mset, ok := prog.methodSets.At(T).(*methodSet)
     51 		if !ok {
     52 			mset = &methodSet{mapping: make(map[string]*Function)}
     53 			prog.methodSets.Set(T, mset)
     54 		}
     55 
     56 		// Get or create SSA method.
     57 		id := sel.Obj().Id()
     58 		fn, ok := mset.mapping[id]
     59 		if !ok {
     60 			obj := sel.Obj().(*types.Func)
     61 			needsPromotion := len(sel.Index()) > 1
     62 			needsIndirection := !isPointer(recvType(obj)) && isPointer(T)
     63 			if needsPromotion || needsIndirection {
     64 				fn = createWrapper(prog, toSelection(sel), nil)
     65 				fn.buildshared = b.shared()
     66 				b.enqueue(fn)
     67 			} else {
     68 				fn = prog.objectMethod(obj, nil, &b)
     69 			}
     70 			if fn.Signature.Recv() == nil {
     71 				panic(fn)
     72 			}
     73 			mset.mapping[id] = fn
     74 		} else {
     75 			b.waitForSharedFunction(fn)
     76 		}
     77 
     78 		return fn
     79 	}()
     80 
     81 	b.iterate()
     82 
     83 	return m
     84 }
     85 
     86 // objectMethod returns the Function for a given method symbol.
     87 // The symbol may be an instance of a generic function. It need not
     88 // belong to an existing SSA package created by a call to
     89 // prog.CreatePackage.
     90 //
     91 // objectMethod panics if the function is not a method.
     92 //
     93 // Acquires prog.objectMethodsMu.
     94 func (prog *Program) objectMethod(obj *types.Func, targs []types.Type, b *builder) *Function {
     95 	sig := obj.Type().(*types.Signature)
     96 	if sig.Recv() == nil {
     97 		panic("not a method: " + obj.String())
     98 	}
     99 
    100 	// Instantiation of generic?
    101 	if orig := obj.Origin(); orig != obj || len(targs) > 0 {
    102 		return prog.objectMethod(orig, nil, b).instance(receiverTypeArgs(obj), targs, b)
    103 	}
    104 
    105 	// Belongs to a created package?
    106 	if fn := prog.FuncValue(obj); fn != nil {
    107 		return fn
    108 	}
    109 
    110 	// Consult/update cache of methods created from types.Func.
    111 	prog.objectMethodsMu.Lock()
    112 	defer prog.objectMethodsMu.Unlock()
    113 	fn, ok := prog.objectMethods[obj]
    114 	if !ok {
    115 		fn = createFunction(prog, obj, obj.Name(), nil, nil, "")
    116 		fn.Synthetic = "from type information (on demand)"
    117 		fn.buildshared = b.shared()
    118 		b.enqueue(fn)
    119 
    120 		if prog.objectMethods == nil {
    121 			prog.objectMethods = make(map[*types.Func]*Function)
    122 		}
    123 		prog.objectMethods[obj] = fn
    124 	} else {
    125 		b.waitForSharedFunction(fn)
    126 	}
    127 	return fn
    128 }
    129 
    130 // LookupMethod returns the implementation of the method of type T
    131 // identified by (pkg, name).  It returns nil if the method exists but
    132 // is an interface method or generic method, and panics if T has no such method.
    133 func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
    134 	sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
    135 	if sel == nil {
    136 		panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
    137 	}
    138 	return prog.MethodValue(sel)
    139 }
    140 
    141 // methodSet contains the (concrete) methods of a concrete type (non-interface, non-parameterized).
    142 type methodSet struct {
    143 	mapping map[string]*Function // populated lazily
    144 }
    145 
    146 // RuntimeTypes returns a new unordered slice containing all types in
    147 // the program for which a runtime type is required.
    148 //
    149 // A runtime type is required for any non-parameterized, non-interface
    150 // type that is converted to an interface, or for any type (including
    151 // interface types) derivable from one through reflection.
    152 //
    153 // The methods of such types may be reachable through reflection or
    154 // interface calls even if they are never called directly.
    155 //
    156 // Thread-safe.
    157 //
    158 // Acquires prog.makeInterfaceTypesMu.
    159 func (prog *Program) RuntimeTypes() []types.Type {
    160 	prog.makeInterfaceTypesMu.Lock()
    161 	defer prog.makeInterfaceTypesMu.Unlock()
    162 
    163 	// Compute the derived types on demand, since many SSA clients
    164 	// never call RuntimeTypes, and those that do typically call
    165 	// it once (often within ssautil.AllFunctions, which will
    166 	// eventually not use it; see Go issue #69291.) This
    167 	// eliminates the need to eagerly compute all the element
    168 	// types during SSA building.
    169 	var runtimeTypes []types.Type
    170 	var set typeutil.Map // for de-duping identical types
    171 	for t := range prog.makeInterfaceTypes {
    172 		typesinternal.ForEachElement(prog.MethodSets.MethodSet, t, func(t types.Type, access bool) bool {
    173 			if !access {
    174 				return false // inaccessible to reflection
    175 			}
    176 			seen, _ := set.Set(t, true).(bool)
    177 			if !seen {
    178 				runtimeTypes = append(runtimeTypes, t)
    179 			}
    180 			return seen
    181 		})
    182 	}
    183 
    184 	return runtimeTypes
    185 }