github.com/goplus/gop@v1.2.6/cl/func_type_and_var.go (about)

     1  /*
     2   * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cl
    18  
    19  import (
    20  	"go/constant"
    21  	"go/types"
    22  	"log"
    23  	"math/big"
    24  	"strconv"
    25  
    26  	"github.com/goplus/gogen"
    27  	"github.com/goplus/gop/ast"
    28  	"github.com/goplus/gop/token"
    29  )
    30  
    31  // -----------------------------------------------------------------------------
    32  
    33  func toRecv(ctx *blockCtx, recv *ast.FieldList) *types.Var {
    34  	v := recv.List[0]
    35  	var name string
    36  	if len(v.Names) > 0 {
    37  		name = v.Names[0].Name
    38  	}
    39  	typ, star := getRecvType(v.Type)
    40  	id, ok := typ.(*ast.Ident)
    41  	if !ok {
    42  		panic("TODO: getRecvType")
    43  	}
    44  	t := toIdentType(ctx, id)
    45  	if star {
    46  		t = types.NewPointer(t)
    47  	}
    48  	ret := ctx.pkg.NewParam(v.Pos(), name, t)
    49  	if rec := ctx.recorder(); rec != nil {
    50  		dRecv := recv.List[0]
    51  		if names := dRecv.Names; len(names) == 1 {
    52  			rec.Def(names[0], ret)
    53  		}
    54  	}
    55  	return ret
    56  }
    57  
    58  func getRecvTypeName(ctx *pkgCtx, recv *ast.FieldList, handleErr bool) (string, bool) {
    59  	typ, _ := getRecvType(recv.List[0].Type)
    60  	if t, ok := typ.(*ast.Ident); ok {
    61  		return t.Name, true
    62  	}
    63  	if handleErr {
    64  		src := ctx.LoadExpr(typ)
    65  		ctx.handleErrorf(typ.Pos(), "invalid receiver type %v (%v is not a defined type)", src, src)
    66  	}
    67  	return "", false
    68  }
    69  
    70  func toResults(ctx *blockCtx, in *ast.FieldList) *types.Tuple {
    71  	if in == nil {
    72  		return nil
    73  	}
    74  	flds := in.List
    75  	n := len(flds)
    76  	args := make([]*types.Var, 0, n)
    77  	for _, fld := range flds {
    78  		args = toParam(ctx, fld, args)
    79  	}
    80  	return types.NewTuple(args...)
    81  }
    82  
    83  func toParams(ctx *blockCtx, flds []*ast.Field) (typ *types.Tuple, variadic bool) {
    84  	n := len(flds)
    85  	if n == 0 {
    86  		return nil, false
    87  	}
    88  	args := make([]*types.Var, 0, n)
    89  	for _, fld := range flds {
    90  		args = toParam(ctx, fld, args)
    91  	}
    92  	_, ok := flds[n-1].Type.(*ast.Ellipsis)
    93  	return types.NewTuple(args...), ok
    94  }
    95  
    96  func toParam(ctx *blockCtx, fld *ast.Field, args []*gogen.Param) []*gogen.Param {
    97  	typ := toType(ctx, fld.Type)
    98  	pkg := ctx.pkg
    99  	if len(fld.Names) == 0 {
   100  		return append(args, pkg.NewParam(fld.Pos(), "", typ))
   101  	}
   102  	for _, name := range fld.Names {
   103  		param := pkg.NewParam(name.Pos(), name.Name, typ)
   104  		args = append(args, param)
   105  		if rec := ctx.recorder(); rec != nil {
   106  			rec.Def(name, param)
   107  		}
   108  	}
   109  	return args
   110  }
   111  
   112  // -----------------------------------------------------------------------------
   113  
   114  func toType(ctx *blockCtx, typ ast.Expr) (t types.Type) {
   115  	if rec := ctx.recorder(); rec != nil {
   116  		defer func() {
   117  			rec.recordType(typ, t)
   118  		}()
   119  	}
   120  	switch v := typ.(type) {
   121  	case *ast.Ident:
   122  		ctx.idents = append(ctx.idents, v)
   123  		defer func() {
   124  			ctx.idents = ctx.idents[:len(ctx.idents)-1]
   125  		}()
   126  		typ := toIdentType(ctx, v)
   127  		if ctx.inInst == 0 {
   128  			if t, ok := typ.(*types.Named); ok {
   129  				if namedIsTypeParams(ctx, t) {
   130  					pos := ctx.idents[0].Pos()
   131  					for _, i := range ctx.idents {
   132  						if i.Name == v.Name {
   133  							pos = i.Pos()
   134  							break
   135  						}
   136  					}
   137  					ctx.handleErrorf(pos, "cannot use generic type %v without instantiation", t.Obj().Type())
   138  					return types.Typ[types.Invalid]
   139  				}
   140  			}
   141  		}
   142  		return typ
   143  	case *ast.StarExpr:
   144  		elem := toType(ctx, v.X)
   145  		return types.NewPointer(elem)
   146  	case *ast.ArrayType:
   147  		return toArrayType(ctx, v)
   148  	case *ast.InterfaceType:
   149  		return toInterfaceType(ctx, v)
   150  	case *ast.Ellipsis:
   151  		elem := toType(ctx, v.Elt)
   152  		return types.NewSlice(elem)
   153  	case *ast.MapType:
   154  		return toMapType(ctx, v)
   155  	case *ast.StructType:
   156  		return toStructType(ctx, v)
   157  	case *ast.ChanType:
   158  		return toChanType(ctx, v)
   159  	case *ast.FuncType:
   160  		return toFuncType(ctx, v, nil, nil)
   161  	case *ast.SelectorExpr:
   162  		typ := toExternalType(ctx, v)
   163  		if ctx.inInst == 0 {
   164  			if t, ok := typ.(*types.Named); ok {
   165  				if namedIsTypeParams(ctx, t) {
   166  					panic(ctx.newCodeErrorf(v.Pos(), "cannot use generic type %v without instantiation", t.Obj().Type()))
   167  				}
   168  			}
   169  		}
   170  		return typ
   171  	case *ast.ParenExpr:
   172  		return toType(ctx, v.X)
   173  	case *ast.BinaryExpr:
   174  		return toBinaryExprType(ctx, v)
   175  	case *ast.UnaryExpr:
   176  		return toUnaryExprType(ctx, v)
   177  	case *ast.IndexExpr:
   178  		return toIndexType(ctx, v)
   179  	case *ast.IndexListExpr:
   180  		return toIndexListType(ctx, v)
   181  	default:
   182  		ctx.handleErrorf(v.Pos(), "toType unexpected: %T", v)
   183  		return types.Typ[types.Invalid]
   184  	}
   185  }
   186  
   187  var (
   188  	typesChanDirs = [...]types.ChanDir{
   189  		ast.RECV:            types.RecvOnly,
   190  		ast.SEND:            types.SendOnly,
   191  		ast.SEND | ast.RECV: types.SendRecv,
   192  	}
   193  )
   194  
   195  func toChanType(ctx *blockCtx, v *ast.ChanType) *types.Chan {
   196  	return types.NewChan(typesChanDirs[v.Dir], toType(ctx, v.Value))
   197  }
   198  
   199  func toExternalType(ctx *blockCtx, v *ast.SelectorExpr) types.Type {
   200  	id := v.X.(*ast.Ident)
   201  	name := id.Name
   202  	if pi, ok := ctx.findImport(name); ok {
   203  		rec := ctx.recorder()
   204  		if rec != nil {
   205  			rec.Use(id, pi.pkgName)
   206  		}
   207  		o := pi.TryRef(v.Sel.Name)
   208  		if t, ok := o.(*types.TypeName); ok {
   209  			if rec != nil {
   210  				rec.Use(v.Sel, t)
   211  			}
   212  			return t.Type()
   213  		}
   214  		ctx.handleErrorf(v.Pos(), "%s.%s is not a type", name, v.Sel.Name)
   215  	} else {
   216  		ctx.handleErrorf(v.Pos(), "undefined: %s", name)
   217  	}
   218  	return types.Typ[types.Invalid]
   219  }
   220  
   221  /*-----------------------------------------------------------------------------
   222  
   223  Name context:
   224  - type
   225  - pkgRef.type
   226  - spx.type
   227  
   228  // ---------------------------------------------------------------------------*/
   229  
   230  func toIdentType(ctx *blockCtx, ident *ast.Ident) (ret types.Type) {
   231  	var obj types.Object
   232  	if rec := ctx.recorder(); rec != nil {
   233  		defer func() {
   234  			if obj != nil {
   235  				rec.recordIdent(ident, obj)
   236  			}
   237  		}()
   238  	}
   239  	if ctx.tlookup != nil {
   240  		if typ := ctx.tlookup.Lookup(ident.Name); typ != nil {
   241  			obj = typ.Obj()
   242  			return typ
   243  		}
   244  	}
   245  	v, builtin := lookupType(ctx, ident.Name)
   246  	if isBuiltin(builtin) {
   247  		ctx.handleErrorf(ident.Pos(), "use of builtin %s not in function call", ident.Name)
   248  		return types.Typ[types.Invalid]
   249  	}
   250  	if t, ok := v.(*types.TypeName); ok {
   251  		obj = t
   252  		return t.Type()
   253  	}
   254  	if v, _ := lookupPkgRef(ctx, gogen.PkgRef{}, ident, objPkgRef); v != nil {
   255  		if t, ok := v.(*types.TypeName); ok {
   256  			obj = t
   257  			return t.Type()
   258  		}
   259  	}
   260  	ctx.handleErrorf(ident.Pos(), "%s is not a type", ident.Name)
   261  	return types.Typ[types.Invalid]
   262  }
   263  
   264  // TODO: optimization
   265  func lookupType(ctx *blockCtx, name string) (types.Object, types.Object) {
   266  	at, o := ctx.cb.Scope().LookupParent(name, token.NoPos)
   267  	if o != nil && at != types.Universe {
   268  		if debugLookup {
   269  			log.Println("==> LookupParent", name, "=>", o)
   270  		}
   271  		return o, nil
   272  	}
   273  	if ctx.loadSymbol(name) {
   274  		if v := ctx.pkg.Types.Scope().Lookup(name); v != nil {
   275  			if debugLookup {
   276  				log.Println("==> Lookup (LoadSymbol)", name, "=>", v)
   277  			}
   278  			return v, nil
   279  		}
   280  	}
   281  	if obj := ctx.pkg.Builtin().TryRef(name); obj != nil {
   282  		return obj, o
   283  	}
   284  	return o, o
   285  }
   286  
   287  type checkRedecl struct {
   288  	// ctx *blockCtx
   289  	names map[string]token.Pos
   290  }
   291  
   292  func newCheckRedecl() *checkRedecl {
   293  	p := &checkRedecl{names: make(map[string]token.Pos)}
   294  	return p
   295  }
   296  
   297  func (p *checkRedecl) chkRedecl(ctx *blockCtx, name string, pos token.Pos) bool {
   298  	if name == "_" {
   299  		return false
   300  	}
   301  	if opos, ok := p.names[name]; ok {
   302  		ctx.handleErrorf(
   303  			pos, "%v redeclared\n\t%v other declaration of %v",
   304  			name, ctx.Position(opos), name)
   305  		return true
   306  	}
   307  	p.names[name] = pos
   308  	return false
   309  }
   310  
   311  func toStructType(ctx *blockCtx, v *ast.StructType) *types.Struct {
   312  	pkg := ctx.pkg.Types
   313  	fieldList := v.Fields.List
   314  	fields := make([]*types.Var, 0, len(fieldList))
   315  	tags := make([]string, 0, len(fieldList))
   316  	chk := newCheckRedecl()
   317  	rec := ctx.recorder()
   318  	for _, field := range fieldList {
   319  		typ := toType(ctx, field.Type)
   320  		if len(field.Names) == 0 { // embedded
   321  			name := getTypeName(typ)
   322  			if chk.chkRedecl(ctx, name, field.Type.Pos()) {
   323  				continue
   324  			}
   325  			if t, ok := typ.(*types.Named); ok { // #1196: embedded type should ensure loaded
   326  				ctx.loadNamed(ctx.pkg, t)
   327  			}
   328  			ident := parseTypeEmbedName(field.Type)
   329  			fld := types.NewField(ident.NamePos, pkg, name, typ, true)
   330  			fields = append(fields, fld)
   331  			tags = append(tags, toFieldTag(field.Tag))
   332  			if rec != nil {
   333  				rec.Def(ident, fld)
   334  			}
   335  			continue
   336  		}
   337  		for _, name := range field.Names {
   338  			if chk.chkRedecl(ctx, name.Name, name.NamePos) {
   339  				continue
   340  			}
   341  			fld := types.NewField(name.NamePos, pkg, name.Name, typ, false)
   342  			fields = append(fields, fld)
   343  			tags = append(tags, toFieldTag(field.Tag))
   344  			if rec != nil {
   345  				rec.Def(name, fld)
   346  			}
   347  		}
   348  	}
   349  	return types.NewStruct(fields, tags)
   350  }
   351  
   352  func toFieldTag(v *ast.BasicLit) string {
   353  	if v != nil {
   354  		tag, err := strconv.Unquote(v.Value)
   355  		if err != nil {
   356  			log.Panicln("TODO: toFieldTag -", err)
   357  		}
   358  		return tag
   359  	}
   360  	return ""
   361  }
   362  
   363  func getTypeName(typ types.Type) string {
   364  	if t, ok := typ.(*types.Pointer); ok {
   365  		typ = t.Elem()
   366  	}
   367  	switch t := typ.(type) {
   368  	case *types.Named:
   369  		return t.Obj().Name()
   370  	case *types.Basic:
   371  		return t.Name()
   372  	default:
   373  		panic("TODO: getTypeName")
   374  	}
   375  }
   376  
   377  func toMapType(ctx *blockCtx, v *ast.MapType) *types.Map {
   378  	key := toType(ctx, v.Key)
   379  	val := toType(ctx, v.Value)
   380  	return types.NewMap(key, val)
   381  }
   382  
   383  func toArrayType(ctx *blockCtx, v *ast.ArrayType) types.Type {
   384  	elem := toType(ctx, v.Elt)
   385  	if v.Len == nil {
   386  		return types.NewSlice(elem)
   387  	}
   388  	if _, ok := v.Len.(*ast.Ellipsis); ok {
   389  		return types.NewArray(elem, -1) // A negative length indicates an unknown length
   390  	}
   391  	return types.NewArray(elem, toInt64(ctx, v.Len, "non-constant array bound %s"))
   392  }
   393  
   394  func toInt64(ctx *blockCtx, e ast.Expr, emsg string) int64 {
   395  	cb := ctx.pkg.ConstStart()
   396  	compileExpr(ctx, e)
   397  	tv := cb.EndConst()
   398  	if val := tv.CVal; val != nil {
   399  		if val.Kind() == constant.Float {
   400  			if v, ok := constant.Val(val).(*big.Rat); ok && v.IsInt() {
   401  				return v.Num().Int64()
   402  			}
   403  		} else if v, ok := constant.Int64Val(val); ok {
   404  			return v
   405  		}
   406  	}
   407  	src := ctx.LoadExpr(e)
   408  	panic(ctx.newCodeErrorf(e.Pos(), emsg, src))
   409  }
   410  
   411  func toInterfaceType(ctx *blockCtx, v *ast.InterfaceType) types.Type {
   412  	methodsList := v.Methods.List
   413  	if methodsList == nil {
   414  		return types.NewInterfaceType(nil, nil)
   415  	}
   416  	var rec = ctx.recorder()
   417  	var pkg = ctx.pkg.Types
   418  	var methods []*types.Func
   419  	var embeddeds []types.Type
   420  	for _, m := range methodsList {
   421  		if len(m.Names) == 0 { // embedded
   422  			typ := toType(ctx, m.Type)
   423  			if t, ok := typ.(*types.Named); ok { // #1198: embedded type should ensure loaded
   424  				ctx.loadNamed(ctx.pkg, t)
   425  			}
   426  			embeddeds = append(embeddeds, typ)
   427  			continue
   428  		}
   429  		name := m.Names[0]
   430  		sig := toFuncType(ctx, m.Type.(*ast.FuncType), nil, nil)
   431  		mthd := types.NewFunc(name.NamePos, pkg, name.Name, sig)
   432  		methods = append(methods, mthd)
   433  		if rec != nil {
   434  			rec.Def(name, mthd)
   435  		}
   436  	}
   437  	intf := types.NewInterfaceType(methods, embeddeds).Complete()
   438  	return intf
   439  }
   440  
   441  func instantiate(ctx *blockCtx, exprX ast.Expr, indices ...ast.Expr) types.Type {
   442  	ctx.inInst++
   443  	defer func() {
   444  		ctx.inInst--
   445  	}()
   446  
   447  	x := toType(ctx, exprX)
   448  	idx := make([]types.Type, len(indices))
   449  	for i, index := range indices {
   450  		idx[i] = toType(ctx, index)
   451  	}
   452  	typ := ctx.pkg.Instantiate(x, idx, exprX)
   453  	if rec := ctx.recorder(); rec != nil {
   454  		rec.instantiate(exprX, x, typ)
   455  	}
   456  	return typ
   457  }
   458  
   459  func toIndexType(ctx *blockCtx, v *ast.IndexExpr) types.Type {
   460  	return instantiate(ctx, v.X, v.Index)
   461  }
   462  
   463  func toIndexListType(ctx *blockCtx, v *ast.IndexListExpr) types.Type {
   464  	return instantiate(ctx, v.X, v.Indices...)
   465  }
   466  
   467  // -----------------------------------------------------------------------------
   468  
   469  func toString(l *ast.BasicLit) string {
   470  	if l.Kind == token.STRING {
   471  		s, err := strconv.Unquote(l.Value)
   472  		if err == nil {
   473  			return s
   474  		}
   475  	}
   476  	panic("TODO: toString - convert ast.BasicLit to string failed")
   477  }
   478  
   479  // -----------------------------------------------------------------------------