github.com/goplus/llgo@v0.8.3/ssa/type_cvt.go (about)

     1  /*
     2   * Copyright (c) 2024 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 ssa
    18  
    19  import (
    20  	"fmt"
    21  	"go/token"
    22  	"go/types"
    23  	"unsafe"
    24  )
    25  
    26  // -----------------------------------------------------------------------------
    27  
    28  type goTypes struct {
    29  	typs  map[unsafe.Pointer]unsafe.Pointer
    30  	named map[string]*types.Named
    31  }
    32  
    33  func newGoTypes() goTypes {
    34  	typs := make(map[unsafe.Pointer]unsafe.Pointer)
    35  	named := make(map[string]*types.Named)
    36  	return goTypes{typs, named}
    37  }
    38  
    39  type Background int
    40  
    41  const (
    42  	inUnknown Background = iota
    43  	InGo
    44  	InC
    45  	InPython
    46  )
    47  
    48  // Type convert a Go/C type into raw type.
    49  // C type = raw type
    50  // Go type: convert to raw type (because of closure)
    51  func (p Program) Type(typ types.Type, bg Background) Type {
    52  	if bg == InGo {
    53  		typ, _ = p.gocvt.cvtType(typ)
    54  	}
    55  	return p.rawType(typ)
    56  }
    57  
    58  // FuncDecl converts a Go/C function declaration into raw type.
    59  func (p Program) FuncDecl(sig *types.Signature, bg Background) Type {
    60  	recv := sig.Recv()
    61  	if bg == InGo {
    62  		sig = p.gocvt.cvtFunc(sig, recv)
    63  	} else if recv != nil { // even in C, we need to add ctx for method
    64  		sig = FuncAddCtx(recv, sig)
    65  	}
    66  	return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFuncDecl}
    67  }
    68  
    69  /*
    70  // cvtCxFunc converts a C extended function type into raw type.
    71  func cvtCxFunc(sig *types.Signature, recv *types.Var) *types.Signature {
    72  	if sig.Variadic() {
    73  			// convert printf-like function type
    74  			tParams := sig.Params()
    75  			n := tParams.Len()
    76  			params := make([]*types.Var, n)
    77  			n--
    78  			for i := 0; i < n; i++ {
    79  				params[i] = tParams.At(i)
    80  			}
    81  			params[n] = VArg()
    82  			sig = types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), true)
    83  		panic("todo")
    84  	}
    85  	sig = FuncAddCtx(recv, sig)
    86  	return sig
    87  }
    88  */
    89  
    90  // Closure creates a closture type for a function.
    91  func (p Program) Closure(fn Type) Type {
    92  	sig := fn.raw.Type.(*types.Signature)
    93  	closure := p.gocvt.cvtClosure(sig)
    94  	return p.rawType(closure)
    95  }
    96  
    97  func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) {
    98  	switch t := typ.(type) {
    99  	case *types.Basic:
   100  	case *types.Pointer:
   101  		if elem, cvt := p.cvtType(t.Elem()); cvt {
   102  			return types.NewPointer(elem), true
   103  		}
   104  	case *types.Interface:
   105  		return p.cvtInterface(t)
   106  	case *types.Slice:
   107  		if elem, cvt := p.cvtType(t.Elem()); cvt {
   108  			return types.NewSlice(elem), true
   109  		}
   110  	case *types.Map:
   111  		key, cvt1 := p.cvtType(t.Key())
   112  		elem, cvt2 := p.cvtType(t.Elem())
   113  		if cvt1 || cvt2 {
   114  			return types.NewMap(key, elem), true
   115  		}
   116  	case *types.Struct:
   117  		return p.cvtStruct(t)
   118  	case *types.Named:
   119  		return p.cvtNamed(t)
   120  	case *types.Signature:
   121  		return p.cvtClosure(t), true
   122  	case *types.Array:
   123  		if elem, cvt := p.cvtType(t.Elem()); cvt {
   124  			return types.NewArray(elem, t.Len()), true
   125  		}
   126  	case *types.Chan:
   127  		if elem, cvt := p.cvtType(t.Elem()); cvt {
   128  			return types.NewChan(t.Dir(), elem), true
   129  		}
   130  	default:
   131  		panic(fmt.Sprintf("cvtType: unexpected type - %T", typ))
   132  	}
   133  	return typ, false
   134  }
   135  
   136  func (p goTypes) cvtNamed(t *types.Named) (raw *types.Named, cvt bool) {
   137  	if v, ok := p.typs[unsafe.Pointer(t)]; ok {
   138  		raw = (*types.Named)(v)
   139  		cvt = t != raw
   140  		return
   141  	}
   142  	defer func() {
   143  		p.typs[unsafe.Pointer(t)] = unsafe.Pointer(raw)
   144  	}()
   145  	id := t.String()
   146  	if named, ok := p.named[id]; ok {
   147  		return named, false
   148  	}
   149  	named := types.NewNamed(t.Obj(), types.Typ[types.Int], nil)
   150  	p.named[id] = named
   151  	defer delete(p.named, id)
   152  	if tund, cvt := p.cvtType(t.Underlying()); cvt {
   153  		named.SetUnderlying(tund)
   154  		return named, true
   155  	}
   156  	return t, false
   157  }
   158  
   159  func (p goTypes) cvtClosure(sig *types.Signature) *types.Struct {
   160  	ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer])
   161  	raw := p.cvtFunc(sig, ctx)
   162  	flds := []*types.Var{
   163  		types.NewField(token.NoPos, nil, "f", raw, false),
   164  		types.NewField(token.NoPos, nil, "data", types.Typ[types.UnsafePointer], false),
   165  	}
   166  	return types.NewStruct(flds, nil)
   167  }
   168  
   169  func (p goTypes) cvtFunc(sig *types.Signature, recv *types.Var) (raw *types.Signature) {
   170  	if recv != nil {
   171  		sig = FuncAddCtx(recv, sig)
   172  	}
   173  	params, cvt1 := p.cvtTuple(sig.Params())
   174  	results, cvt2 := p.cvtTuple(sig.Results())
   175  	if cvt1 || cvt2 || sig.Variadic() {
   176  		// variadic always is false in raw type for Go function
   177  		return types.NewSignatureType(nil, nil, nil, params, results, false)
   178  	}
   179  	return sig
   180  }
   181  
   182  func (p goTypes) cvtTuple(t *types.Tuple) (*types.Tuple, bool) {
   183  	n := t.Len()
   184  	vars := make([]*types.Var, n)
   185  	needcvt := false
   186  	for i := 0; i < n; i++ {
   187  		v := t.At(i)
   188  		if t, cvt := p.cvtType(v.Type()); cvt {
   189  			v = types.NewParam(v.Pos(), v.Pkg(), v.Name(), t)
   190  			needcvt = true
   191  		}
   192  		vars[i] = v
   193  	}
   194  	if needcvt {
   195  		return types.NewTuple(vars...), true
   196  	}
   197  	return t, false
   198  }
   199  
   200  func (p goTypes) cvtExplicitMethods(typ *types.Interface) ([]*types.Func, bool) {
   201  	n := typ.NumExplicitMethods()
   202  	methods := make([]*types.Func, n)
   203  	needcvt := false
   204  	for i := 0; i < n; i++ {
   205  		m := typ.ExplicitMethod(i)
   206  		sig := m.Type().(*types.Signature)
   207  		if raw := p.cvtFunc(sig, nil); sig != raw {
   208  			m = types.NewFunc(m.Pos(), m.Pkg(), m.Name(), raw)
   209  			needcvt = true
   210  		}
   211  		methods[i] = m
   212  	}
   213  	return methods, needcvt
   214  }
   215  
   216  func (p goTypes) cvtEmbeddedTypes(typ *types.Interface) ([]types.Type, bool) {
   217  	n := typ.NumEmbeddeds()
   218  	embeddeds := make([]types.Type, n)
   219  	needcvt := false
   220  	for i := 0; i < n; i++ {
   221  		t := typ.EmbeddedType(i)
   222  		if raw, cvt := p.cvtType(t); cvt {
   223  			t = raw
   224  			needcvt = true
   225  		}
   226  		embeddeds[i] = t
   227  	}
   228  	return embeddeds, needcvt
   229  }
   230  
   231  func (p goTypes) cvtInterface(typ *types.Interface) (raw *types.Interface, cvt bool) {
   232  	if v, ok := p.typs[unsafe.Pointer(typ)]; ok {
   233  		raw = (*types.Interface)(v)
   234  		cvt = typ != raw
   235  		return
   236  	}
   237  	defer func() {
   238  		p.typs[unsafe.Pointer(typ)] = unsafe.Pointer(raw)
   239  	}()
   240  	methods, cvt1 := p.cvtExplicitMethods(typ)
   241  	embeddeds, cvt2 := p.cvtEmbeddedTypes(typ)
   242  	if cvt1 || cvt2 {
   243  		return types.NewInterfaceType(methods, embeddeds), true
   244  	}
   245  	return typ, false
   246  }
   247  
   248  func (p goTypes) cvtStruct(typ *types.Struct) (raw *types.Struct, cvt bool) {
   249  	if v, ok := p.typs[unsafe.Pointer(typ)]; ok {
   250  		raw = (*types.Struct)(v)
   251  		cvt = typ != raw
   252  		return
   253  	}
   254  	defer func() {
   255  		p.typs[unsafe.Pointer(typ)] = unsafe.Pointer(raw)
   256  	}()
   257  	n := typ.NumFields()
   258  	flds := make([]*types.Var, n)
   259  	needcvt := false
   260  	for i := 0; i < n; i++ {
   261  		f := typ.Field(i)
   262  		if t, cvt := p.cvtType(f.Type()); cvt {
   263  			f = types.NewField(f.Pos(), f.Pkg(), f.Name(), t, f.Anonymous())
   264  			needcvt = true
   265  		}
   266  		flds[i] = f
   267  	}
   268  	if needcvt {
   269  		return types.NewStruct(flds, nil), true
   270  	}
   271  	return typ, false
   272  }
   273  
   274  // -----------------------------------------------------------------------------
   275  
   276  // FuncAddCtx adds a ctx to a function signature.
   277  func FuncAddCtx(ctx *types.Var, sig *types.Signature) *types.Signature {
   278  	tParams := sig.Params()
   279  	nParams := tParams.Len()
   280  	params := make([]*types.Var, nParams+1)
   281  	params[0] = ctx
   282  	for i := 0; i < nParams; i++ {
   283  		params[i+1] = tParams.At(i)
   284  	}
   285  	return types.NewSignatureType(
   286  		nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
   287  }
   288  
   289  // -----------------------------------------------------------------------------