github.com/goplus/igop@v0.25.0/types_go118.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 /* 5 * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package igop 21 22 import ( 23 "go/ast" 24 "go/types" 25 "reflect" 26 "strconv" 27 "strings" 28 29 "golang.org/x/tools/go/ssa" 30 "golang.org/x/tools/go/types/typeutil" 31 ) 32 33 const ( 34 enabledTypeParam = true 35 ) 36 37 func hasTypeParam(t types.Type) bool { 38 switch t := t.(type) { 39 case *types.TypeParam: 40 return true 41 case *types.Named: 42 return t.TypeParams() != nil 43 case *types.Signature: 44 return t.TypeParams() != nil 45 } 46 return false 47 } 48 49 type nestedStack struct { 50 targs []string 51 cache []*typeutil.Map 52 } 53 54 func (s *nestedStack) Push(targs string, cache *typeutil.Map) { 55 s.targs = append(s.targs, targs) 56 s.cache = append(s.cache, cache) 57 } 58 59 func (s *nestedStack) Pop() (targs string, cache *typeutil.Map) { 60 n := len(s.targs) 61 if n >= 1 { 62 targs = s.targs[n-1] 63 cache = s.cache[n-1] 64 } 65 s.targs = s.targs[:n-1] 66 s.cache = s.cache[:n-1] 67 return 68 } 69 70 func (r *TypesRecord) typeId(typ types.Type, t reflect.Type) string { 71 path := t.PkgPath() 72 if path == "" { 73 return t.String() 74 } 75 name := path + "." + t.Name() 76 if named, ok := typ.(*types.Named); ok { 77 if n := r.nested[named.Origin()]; n != 0 { 78 name += "ยท" + strconv.Itoa(n) 79 } 80 } 81 return name 82 } 83 84 func (r *TypesRecord) EnterInstance(fn *ssa.Function) { 85 r.ncache = &typeutil.Map{} 86 tp := fn.TypeParams() 87 for i := 0; i < tp.Len(); i++ { 88 rt, _ := r.ToType(fn.TypeArgs()[i]) 89 r.ncache.Set(tp.At(i), rt) 90 } 91 r.nstack.Push(r.fntargs, r.ncache) 92 r.fntargs = r.parseFuncTypeArgs(fn) 93 } 94 95 func (r *TypesRecord) LeaveInstance(fn *ssa.Function) { 96 r.fntargs, r.ncache = r.nstack.Pop() 97 } 98 99 func (r *TypesRecord) parseFuncTypeArgs(fn *ssa.Function) (targs string) { 100 typeargs := fn.TypeArgs() 101 if len(typeargs) == 0 { 102 return 103 } 104 var args []string 105 for _, typ := range typeargs { 106 rt, _ := r.ToType(typ) 107 args = append(args, r.typeId(typ, rt)) 108 } 109 return strings.Join(args, ",") 110 } 111 112 func (r *TypesRecord) extractNamed(named *types.Named, totype bool) (pkgpath string, name string, typeargs bool, nested bool) { 113 obj := named.Obj() 114 if pkg := obj.Pkg(); pkg != nil { 115 if pkg.Name() == "main" { 116 pkgpath = "main" 117 } else { 118 pkgpath = pkg.Path() 119 } 120 } 121 if r.fntargs != "" && r.nested[named.Origin()] != 0 { 122 nested = true 123 } 124 name = obj.Name() 125 var ids string = r.fntargs 126 if args := named.TypeArgs(); args != nil { 127 typeargs = true 128 var targs []string 129 for i := 0; i < args.Len(); i++ { 130 if totype { 131 typ := args.At(i) 132 rt, _ := r.ToType(typ) 133 targs = append(targs, r.typeId(typ, rt)) 134 } else { 135 targs = append(targs, args.At(i).String()) 136 } 137 } 138 if ids != "" { 139 ids += ";" 140 } 141 ids += strings.Join(targs, ",") 142 } 143 if ids != "" { 144 name += "[" + ids + "]" 145 } 146 return 147 } 148 149 func (r *TypesRecord) LookupReflect(typ types.Type) (rt reflect.Type, ok bool, nested bool) { 150 rt, ok = r.loader.LookupReflect(typ) 151 if !ok { 152 if r.ncache != nil { 153 if rt := r.ncache.At(typ); rt != nil { 154 return rt.(reflect.Type), true, true 155 } 156 } 157 n := len(r.nstack.cache) 158 for i := n; i > 0; i-- { 159 if rt := r.nstack.cache[i-1].At(typ); rt != nil { 160 return rt.(reflect.Type), true, true 161 } 162 } 163 if rt := r.tcache.At(typ); rt != nil { 164 return rt.(reflect.Type), true, false 165 } 166 } 167 return 168 } 169 170 func (r *TypesLoader) hasTypeArgs(rt reflect.Type) bool { 171 switch rt.Kind() { 172 case reflect.Pointer: 173 return r.hasTypeArgs(rt.Elem()) 174 case reflect.Slice: 175 return r.hasTypeArgs(rt.Elem()) 176 case reflect.Array: 177 return r.hasTypeArgs(rt.Elem()) 178 case reflect.Chan: 179 return r.hasTypeArgs(rt.Elem()) 180 case reflect.Map: 181 return r.hasTypeArgs(rt.Key()) || r.hasTypeArgs(rt.Elem()) 182 case reflect.Struct: 183 if pkgPath := rt.PkgPath(); pkgPath != "" { 184 if pkg, ok := r.packages[pkgPath]; ok && pkg.Complete() { 185 name := rt.Name() 186 var typeArgs string 187 if n := strings.Index(name, "["); n != -1 { 188 if end := strings.LastIndex(name, "]"); end != -1 { 189 typeArgs = name[n+1 : end] 190 name = name[:n] 191 } 192 } 193 if obj := pkg.Scope().Lookup(name); obj != nil && len(typeArgs) > 0 { 194 return true 195 } 196 } 197 } 198 } 199 return false 200 } 201 202 func newTypesInfo() *types.Info { 203 return &types.Info{ 204 Types: make(map[ast.Expr]types.TypeAndValue), 205 Defs: make(map[*ast.Ident]types.Object), 206 Uses: make(map[*ast.Ident]types.Object), 207 Implicits: make(map[ast.Node]types.Object), 208 Scopes: make(map[ast.Node]*types.Scope), 209 Selections: make(map[*ast.SelectorExpr]*types.Selection), 210 Instances: make(map[*ast.Ident]types.Instance), 211 } 212 }