github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/ssa/methods14.go (about)

     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  // +build !go1.5
     6  
     7  package ssa
     8  
     9  // This file defines utilities for population of method sets.
    10  
    11  import (
    12  	"fmt"
    13  
    14  	"golang.org/x/tools/go/types"
    15  )
    16  
    17  // MethodValue returns the Function implementing method sel, building
    18  // wrapper methods on demand.  It returns nil if sel denotes an
    19  // abstract (interface) method.
    20  //
    21  // Precondition: sel.Kind() == MethodVal.
    22  //
    23  // Thread-safe.
    24  //
    25  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
    26  //
    27  func (prog *Program) MethodValue(sel *types.Selection) *Function {
    28  	if sel.Kind() != types.MethodVal {
    29  		panic(fmt.Sprintf("Method(%s) kind != MethodVal", sel))
    30  	}
    31  	T := sel.Recv()
    32  	if isInterface(T) {
    33  		return nil // abstract method
    34  	}
    35  	if prog.mode&LogSource != 0 {
    36  		defer logStack("Method %s %v", T, sel)()
    37  	}
    38  
    39  	prog.methodsMu.Lock()
    40  	defer prog.methodsMu.Unlock()
    41  
    42  	return prog.addMethod(prog.createMethodSet(T), sel)
    43  }
    44  
    45  // LookupMethod returns the implementation of the method of type T
    46  // identified by (pkg, name).  It returns nil if the method exists but
    47  // is abstract, and panics if T has no such method.
    48  //
    49  func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
    50  	sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
    51  	if sel == nil {
    52  		panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
    53  	}
    54  	return prog.MethodValue(sel)
    55  }
    56  
    57  // methodSet contains the (concrete) methods of a non-interface type.
    58  type methodSet struct {
    59  	mapping  map[string]*Function // populated lazily
    60  	complete bool                 // mapping contains all methods
    61  }
    62  
    63  // Precondition: !isInterface(T).
    64  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
    65  func (prog *Program) createMethodSet(T types.Type) *methodSet {
    66  	mset, ok := prog.methodSets.At(T).(*methodSet)
    67  	if !ok {
    68  		mset = &methodSet{mapping: make(map[string]*Function)}
    69  		prog.methodSets.Set(T, mset)
    70  	}
    71  	return mset
    72  }
    73  
    74  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
    75  func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function {
    76  	if sel.Kind() == types.MethodExpr {
    77  		panic(sel)
    78  	}
    79  	id := sel.Obj().Id()
    80  	fn := mset.mapping[id]
    81  	if fn == nil {
    82  		obj := sel.Obj().(*types.Func)
    83  
    84  		needsPromotion := len(sel.Index()) > 1
    85  		needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv())
    86  		if needsPromotion || needsIndirection {
    87  			fn = makeWrapper(prog, sel)
    88  		} else {
    89  			fn = prog.declaredFunc(obj)
    90  		}
    91  		if fn.Signature.Recv() == nil {
    92  			panic(fn) // missing receiver
    93  		}
    94  		mset.mapping[id] = fn
    95  	}
    96  	return fn
    97  }
    98  
    99  // RuntimeTypes returns a new unordered slice containing all
   100  // concrete types in the program for which a complete (non-empty)
   101  // method set is required at run-time.
   102  //
   103  // Thread-safe.
   104  //
   105  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
   106  //
   107  func (prog *Program) RuntimeTypes() []types.Type {
   108  	prog.methodsMu.Lock()
   109  	defer prog.methodsMu.Unlock()
   110  
   111  	var res []types.Type
   112  	prog.methodSets.Iterate(func(T types.Type, v interface{}) {
   113  		if v.(*methodSet).complete {
   114  			res = append(res, T)
   115  		}
   116  	})
   117  	return res
   118  }
   119  
   120  // declaredFunc returns the concrete function/method denoted by obj.
   121  // Panic ensues if there is none.
   122  //
   123  func (prog *Program) declaredFunc(obj *types.Func) *Function {
   124  	if v := prog.packageLevelValue(obj); v != nil {
   125  		return v.(*Function)
   126  	}
   127  	panic("no concrete method: " + obj.String())
   128  }
   129  
   130  // needMethodsOf ensures that runtime type information (including the
   131  // complete method set) is available for the specified type T and all
   132  // its subcomponents.
   133  //
   134  // needMethodsOf must be called for at least every type that is an
   135  // operand of some MakeInterface instruction, and for the type of
   136  // every exported package member.
   137  //
   138  // Precondition: T is not a method signature (*Signature with Recv()!=nil).
   139  //
   140  // Thread-safe.  (Called via emitConv from multiple builder goroutines.)
   141  //
   142  // TODO(adonovan): make this faster.  It accounts for 20% of SSA build time.
   143  //
   144  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
   145  //
   146  func (prog *Program) needMethodsOf(T types.Type) {
   147  	prog.methodsMu.Lock()
   148  	prog.needMethods(T, false)
   149  	prog.methodsMu.Unlock()
   150  }
   151  
   152  // Precondition: T is not a method signature (*Signature with Recv()!=nil).
   153  // Recursive case: skip => don't create methods for T.
   154  //
   155  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
   156  //
   157  func (prog *Program) needMethods(T types.Type, skip bool) {
   158  	// Each package maintains its own set of types it has visited.
   159  	if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
   160  		// needMethods(T) was previously called
   161  		if !prevSkip || skip {
   162  			return // already seen, with same or false 'skip' value
   163  		}
   164  	}
   165  	prog.runtimeTypes.Set(T, skip)
   166  
   167  	tmset := prog.MethodSets.MethodSet(T)
   168  
   169  	if !skip && !isInterface(T) && tmset.Len() > 0 {
   170  		// Create methods of T.
   171  		mset := prog.createMethodSet(T)
   172  		if !mset.complete {
   173  			mset.complete = true
   174  			n := tmset.Len()
   175  			for i := 0; i < n; i++ {
   176  				prog.addMethod(mset, tmset.At(i))
   177  			}
   178  		}
   179  	}
   180  
   181  	// Recursion over signatures of each method.
   182  	for i := 0; i < tmset.Len(); i++ {
   183  		sig := tmset.At(i).Type().(*types.Signature)
   184  		prog.needMethods(sig.Params(), false)
   185  		prog.needMethods(sig.Results(), false)
   186  	}
   187  
   188  	switch t := T.(type) {
   189  	case *types.Basic:
   190  		// nop
   191  
   192  	case *types.Interface:
   193  		// nop---handled by recursion over method set.
   194  
   195  	case *types.Pointer:
   196  		prog.needMethods(t.Elem(), false)
   197  
   198  	case *types.Slice:
   199  		prog.needMethods(t.Elem(), false)
   200  
   201  	case *types.Chan:
   202  		prog.needMethods(t.Elem(), false)
   203  
   204  	case *types.Map:
   205  		prog.needMethods(t.Key(), false)
   206  		prog.needMethods(t.Elem(), false)
   207  
   208  	case *types.Signature:
   209  		if t.Recv() != nil {
   210  			panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
   211  		}
   212  		prog.needMethods(t.Params(), false)
   213  		prog.needMethods(t.Results(), false)
   214  
   215  	case *types.Named:
   216  		// A pointer-to-named type can be derived from a named
   217  		// type via reflection.  It may have methods too.
   218  		prog.needMethods(types.NewPointer(T), false)
   219  
   220  		// Consider 'type T struct{S}' where S has methods.
   221  		// Reflection provides no way to get from T to struct{S},
   222  		// only to S, so the method set of struct{S} is unwanted,
   223  		// so set 'skip' flag during recursion.
   224  		prog.needMethods(t.Underlying(), true)
   225  
   226  	case *types.Array:
   227  		prog.needMethods(t.Elem(), false)
   228  
   229  	case *types.Struct:
   230  		for i, n := 0, t.NumFields(); i < n; i++ {
   231  			prog.needMethods(t.Field(i).Type(), false)
   232  		}
   233  
   234  	case *types.Tuple:
   235  		for i, n := 0, t.Len(); i < n; i++ {
   236  			prog.needMethods(t.At(i).Type(), false)
   237  		}
   238  
   239  	default:
   240  		panic(T)
   241  	}
   242  }