Repository: goplus/gop
Pull request #557 (2020-08-17 15:52:15)

qexp: export type, cl support toExternalType
qexp: support export type
cl: support external type

Go+ code
```
import "image"

println(image.Point{10,20})
println(image.Point{X:10,Y:20})
println(&image.Point{10,20})
println(&image.Point{X:10,Y:20})
println(image.Rectangle{image.Point{1,1},image.Point{100,200}})
println(image.Rectangle{Min:image.Point{1,1},Max:image.Point{100,200}})
println(&image.Rectangle{image.Point{1,1},image.Point{100,200}})
println(&image.Rectangle{Min:image.Point{1,1},Max:image.Point{100,200}})
```
generate Golang code
```
package main

import (
	fmt "fmt"
	image "image"
)

func main() { 
//line ./main.gop:3
	fmt.Println(image.Point{X: 10, Y: 20})
//line ./main.gop:4
	fmt.Println(image.Point{X: 10, Y: 20})
//line ./main.gop:5
	fmt.Println(&image.Point{X: 10, Y: 20})
//line ./main.gop:6
	fmt.Println(&image.Point{X: 10, Y: 20})
//line ./main.gop:7
	fmt.Println(image.Rectangle{Min: image.Point{X: 1, Y: 1}, Max: image.Point{X: 100, Y: 200}})
//line ./main.gop:8
	fmt.Println(image.Rectangle{Min: image.Point{X: 1, Y: 1}, Max: image.Point{X: 100, Y: 200}})
//line ./main.gop:9
	fmt.Println(&image.Rectangle{Min: image.Point{X: 1, Y: 1}, Max: image.Point{X: 100, Y: 200}})
//line ./main.gop:10
	fmt.Println(&image.Rectangle{Min: image.Point{X: 1, Y: 1}, Max: image.Point{X: 100, Y: 200}})
}
```

codecov-commenter: # [Codecov](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=h1) Report
> Merging [#557](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=desc) into [master](https://codecov.io/gh/goplus/gop/commit/5c5c9ef1ca67f59c836009b7e4ce8646ad1bbca5&el=desc) will **decrease** coverage by `0.40%`.
> The diff coverage is `39.75%`.

[![Impacted file tree graph](https://codecov.io/gh/goplus/gop/pull/557/graphs/tree.svg?width=650&height=150&src=pr&token=4qln9Wk3Pn)](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #557      +/-   ##
==========================================
- Coverage   90.22%   89.82%   -0.41%     
==========================================
  Files          40       40              
  Lines       10337    10420      +83     
==========================================
+ Hits         9327     9360      +33     
- Misses        722      772      +50     
  Partials      288      288              
```


| [Impacted Files](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [cl/type\_decl.go](https://codecov.io/gh/goplus/gop/pull/557/diff?src=pr&el=tree#diff-Y2wvdHlwZV9kZWNsLmdv) | `83.26% <0.00%> (-1.46%)` | :arrow_down: |
| [cmd/internal/export/gopkg/exporter.go](https://codecov.io/gh/goplus/gop/pull/557/diff?src=pr&el=tree#diff-Y21kL2ludGVybmFsL2V4cG9ydC9nb3BrZy9leHBvcnRlci5nbw==) | `83.52% <41.02%> (-9.40%)` | :arrow_down: |
| [cmd/internal/export/gopkg/export.go](https://codecov.io/gh/goplus/gop/pull/557/diff?src=pr&el=tree#diff-Y21kL2ludGVybmFsL2V4cG9ydC9nb3BrZy9leHBvcnQuZ28=) | `91.55% <100.00%> (+0.05%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=footer). Last update [5c5c9ef...2cf11de](https://codecov.io/gh/goplus/gop/pull/557?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/cl/expr.go b/cl/expr.go
index 77d805eb..91e99542 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -302,6 +302,8 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit) func() {
 		typStruct := typ.(reflect.Type)
 		ctx.infer.Push(&goValue{t: typStruct})
 		return func() {
+			old := ctx.takeAddr
+			ctx.takeAddr = false
 			for i, elt := range v.Elts {
 				switch e := elt.(type) {
 				case *ast.KeyValueExpr:
@@ -320,7 +322,7 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit) func() {
 					checkType(typVal, ctx.infer.Pop(), ctx.out)
 				}
 			}
-
+			ctx.takeAddr = old
 			if ctx.takeAddr {
 				ctx.out.Struct(reflect.PtrTo(typStruct), len(v.Elts))
 			} else {
diff --git a/cl/type_decl.go b/cl/type_decl.go
index b6b2f129..c06b573b 100644
--- a/cl/type_decl.go
+++ b/cl/type_decl.go
@@ -238,6 +238,20 @@ func toInterfaceType(ctx *blockCtx, v *ast.InterfaceType) iType {
 }
 
 func toExternalType(ctx *blockCtx, v *ast.SelectorExpr) iType {
+	if ident, ok := v.X.(*ast.Ident); ok {
+		if sym, ok := ctx.find(ident.Name); ok {
+			switch t := sym.(type) {
+			case string:
+				pkg := ctx.FindGoPackage(t)
+				if pkg == nil {
+					log.Panicln("toExternalType failed: package not found -", v)
+				}
+				if typ, ok := pkg.FindType(v.Sel.Name); ok {
+					return typ
+				}
+			}
+		}
+	}
 	panic("toExternalType: todo")
 }
 
diff --git a/cmd/internal/export/gopkg/export.go b/cmd/internal/export/gopkg/export.go
index 571cf662..8ede5124 100644
--- a/cmd/internal/export/gopkg/export.go
+++ b/cmd/internal/export/gopkg/export.go
@@ -44,6 +44,8 @@ func exportFunc(e *Exporter, o *types.Func, prefix string) (err error) {
 
 func exportTypeName(e *Exporter, o *types.TypeName) (err error) {
 	t := o.Type().(*types.Named)
+	e.ExportType(o)
+
 	n := t.NumMethods()
 	for i := 0; i < n; i++ {
 		m := t.Method(i)
diff --git a/cmd/internal/export/gopkg/exporter.go b/cmd/internal/export/gopkg/exporter.go
index eecfff1c..dffd2095 100644
--- a/cmd/internal/export/gopkg/exporter.go
+++ b/cmd/internal/export/gopkg/exporter.go
@@ -45,6 +45,11 @@ type exportedConst struct {
 	val  string
 }
 
+type exportedType struct {
+	name string
+	kind string
+}
+
 // Exporter represents a go package exporter.
 type Exporter struct {
 	w            io.Writer
@@ -59,6 +64,7 @@ type Exporter struct {
 	exportFnvs   []exportedFunc
 	exportedVars []exportedVar
 	exportConsts []exportedConst
+	exportTypes  []exportedType
 }
 
 // NewExporter creates a go package exporter.
@@ -363,8 +369,16 @@ func (p *Exporter) ExportVar(typ *types.Var) {
 	p.exportedVars = append(p.exportedVars, exportedVar{name, addr})
 }
 
+// ExportType export a go type
+func (p *Exporter) ExportType(typ *types.TypeName) {
+	name := typ.Name()
+	kind := fmt.Sprintf("%v.TypeOf((*%v)(nil)).Elem()", p.importPkg(reflectPkg), p.importPkg(typ.Pkg())+"."+name)
+	p.exportTypes = append(p.exportTypes, exportedType{name, kind})
+}
+
 var (
-	qspecPkg = types.NewPackage("github.com/goplus/gop/exec.spec", "qspec")
+	qspecPkg   = types.NewPackage("github.com/goplus/gop/exec.spec", "qspec")
+	reflectPkg = types.NewPackage("reflect", "reflect")
 )
 
 // ExportConst exports a go const.
@@ -478,6 +492,19 @@ func registerFns(w io.Writer, pkgDot string, fns []exportedFunc, tag string) {
 	fmt.Fprintf(w, "	)\n")
 }
 
+func registerTypes(w io.Writer, types []exportedType) {
+	if len(types) == 0 {
+		return
+	}
+	fmt.Fprintf(w, `	I.RegisterTypes(
+`)
+	for _, v := range types {
+		fmt.Fprintf(w, `		I.Type("%s", %s),
+`, v.name, v.kind)
+	}
+	fmt.Fprintf(w, "	)\n")
+}
+
 func registerVars(w io.Writer, vars []exportedVar) {
 	if len(vars) == 0 {
 		return
@@ -559,6 +586,7 @@ func (p *Exporter) Close() error {
 	registerFns(p.w, pkgDot, p.exportFns, "Func")
 	registerFns(p.w, pkgDot, p.exportFnvs, "Funcv")
 	registerVars(p.w, p.exportedVars)
+	registerTypes(p.w, p.exportTypes)
 	registerConsts(p.w, p.exportConsts)
 	fmt.Fprintf(p.w, gopkgInitExportFooter)
 	return nil
diff --git a/lib/bytes/gomod_export.go b/lib/bytes/gomod_export.go
index 66ceeb33..2dd5c510 100644
--- a/lib/bytes/gomod_export.go
+++ b/lib/bytes/gomod_export.go
@@ -4,6 +4,7 @@ package bytes
 import (
 	bytes "bytes"
 	io "io"
+	reflect "reflect"
 	unicode "unicode"
 
 	gop "github.com/goplus/gop"
@@ -607,6 +608,10 @@ func init() {
 	I.RegisterVars(
 		I.Var("ErrTooLarge", &bytes.ErrTooLarge),
 	)
+	I.RegisterTypes(
+		I.Type("Buffer", reflect.TypeOf((*bytes.Buffer)(nil)).Elem()),
+		I.Type("Reader", reflect.TypeOf((*bytes.Reader)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("MinRead", qspec.ConstUnboundInt, bytes.MinRead),
 	)
diff --git a/lib/default.go b/lib/default.go
index f5916d05..d12bfc7a 100644
--- a/lib/default.go
+++ b/lib/default.go
@@ -1,5 +1,8 @@
 package lib
 
+//go:generate go run ../cmd/qexp bytes flag fmt io/... log os reflect strconv strings sync/... time
+//go:generate go run ../cmd/qexp github.com/goplus/gop/ast/gopq github.com/goplus/gop/ast/goptest
+
 import (
 	_ "github.com/goplus/gop/lib/builtin" // builtin
 	_ "github.com/goplus/gop/lib/bytes"
diff --git a/lib/flag/gomod_export.go b/lib/flag/gomod_export.go
index cdbb7bf2..aeebfaad 100644
--- a/lib/flag/gomod_export.go
+++ b/lib/flag/gomod_export.go
@@ -4,6 +4,7 @@ package flag
 import (
 	flag "flag"
 	io "io"
+	reflect "reflect"
 	time "time"
 
 	gop "github.com/goplus/gop"
@@ -470,6 +471,13 @@ func init() {
 		I.Var("ErrHelp", &flag.ErrHelp),
 		I.Var("Usage", &flag.Usage),
 	)
+	I.RegisterTypes(
+		I.Type("ErrorHandling", reflect.TypeOf((*flag.ErrorHandling)(nil)).Elem()),
+		I.Type("Flag", reflect.TypeOf((*flag.Flag)(nil)).Elem()),
+		I.Type("FlagSet", reflect.TypeOf((*flag.FlagSet)(nil)).Elem()),
+		I.Type("Getter", reflect.TypeOf((*flag.Getter)(nil)).Elem()),
+		I.Type("Value", reflect.TypeOf((*flag.Value)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("ContinueOnError", qspec.Int, flag.ContinueOnError),
 		I.Const("ExitOnError", qspec.Int, flag.ExitOnError),
diff --git a/lib/fmt/gomod_export.go b/lib/fmt/gomod_export.go
index 4af2a03c..fbd5cdba 100644
--- a/lib/fmt/gomod_export.go
+++ b/lib/fmt/gomod_export.go
@@ -4,6 +4,7 @@ package fmt
 import (
 	fmt "fmt"
 	io "io"
+	reflect "reflect"
 
 	gop "github.com/goplus/gop"
 )
@@ -161,4 +162,12 @@ func init() {
 		I.Funcv("Sscanf", fmt.Sscanf, execSscanf),
 		I.Funcv("Sscanln", fmt.Sscanln, execSscanln),
 	)
+	I.RegisterTypes(
+		I.Type("Formatter", reflect.TypeOf((*fmt.Formatter)(nil)).Elem()),
+		I.Type("GoStringer", reflect.TypeOf((*fmt.GoStringer)(nil)).Elem()),
+		I.Type("ScanState", reflect.TypeOf((*fmt.ScanState)(nil)).Elem()),
+		I.Type("Scanner", reflect.TypeOf((*fmt.Scanner)(nil)).Elem()),
+		I.Type("State", reflect.TypeOf((*fmt.State)(nil)).Elem()),
+		I.Type("Stringer", reflect.TypeOf((*fmt.Stringer)(nil)).Elem()),
+	)
 }
diff --git a/lib/github.com/goplus/gop/ast/gopq/gomod_export.go b/lib/github.com/goplus/gop/ast/gopq/gomod_export.go
index 0d27fb24..8ed386fd 100644
--- a/lib/github.com/goplus/gop/ast/gopq/gomod_export.go
+++ b/lib/github.com/goplus/gop/ast/gopq/gomod_export.go
@@ -4,6 +4,7 @@ package gopq
 import (
 	token "go/token"
 	os "os"
+	reflect "reflect"
 
 	gop "github.com/goplus/gop"
 	gopq "github.com/goplus/gop/ast/gopq"
@@ -193,4 +194,9 @@ func init() {
 		I.Var("ErrNotFound", &gopq.ErrNotFound),
 		I.Var("ErrTooManyNodes", &gopq.ErrTooManyNodes),
 	)
+	I.RegisterTypes(
+		I.Type("Node", reflect.TypeOf((*gopq.Node)(nil)).Elem()),
+		I.Type("NodeEnum", reflect.TypeOf((*gopq.NodeEnum)(nil)).Elem()),
+		I.Type("NodeSet", reflect.TypeOf((*gopq.NodeSet)(nil)).Elem()),
+	)
 }
diff --git a/lib/io/gomod_export.go b/lib/io/gomod_export.go
index 28e65420..1c60b1e7 100644
--- a/lib/io/gomod_export.go
+++ b/lib/io/gomod_export.go
@@ -3,6 +3,7 @@ package io
 
 import (
 	io "io"
+	reflect "reflect"
 
 	gop "github.com/goplus/gop"
 	qspec "github.com/goplus/gop/exec.spec"
@@ -228,6 +229,33 @@ func init() {
 		I.Var("ErrShortWrite", &io.ErrShortWrite),
 		I.Var("ErrUnexpectedEOF", &io.ErrUnexpectedEOF),
 	)
+	I.RegisterTypes(
+		I.Type("ByteReader", reflect.TypeOf((*io.ByteReader)(nil)).Elem()),
+		I.Type("ByteScanner", reflect.TypeOf((*io.ByteScanner)(nil)).Elem()),
+		I.Type("ByteWriter", reflect.TypeOf((*io.ByteWriter)(nil)).Elem()),
+		I.Type("Closer", reflect.TypeOf((*io.Closer)(nil)).Elem()),
+		I.Type("LimitedReader", reflect.TypeOf((*io.LimitedReader)(nil)).Elem()),
+		I.Type("PipeReader", reflect.TypeOf((*io.PipeReader)(nil)).Elem()),
+		I.Type("PipeWriter", reflect.TypeOf((*io.PipeWriter)(nil)).Elem()),
+		I.Type("ReadCloser", reflect.TypeOf((*io.ReadCloser)(nil)).Elem()),
+		I.Type("ReadSeeker", reflect.TypeOf((*io.ReadSeeker)(nil)).Elem()),
+		I.Type("ReadWriteCloser", reflect.TypeOf((*io.ReadWriteCloser)(nil)).Elem()),
+		I.Type("ReadWriteSeeker", reflect.TypeOf((*io.ReadWriteSeeker)(nil)).Elem()),
+		I.Type("ReadWriter", reflect.TypeOf((*io.ReadWriter)(nil)).Elem()),
+		I.Type("Reader", reflect.TypeOf((*io.Reader)(nil)).Elem()),
+		I.Type("ReaderAt", reflect.TypeOf((*io.ReaderAt)(nil)).Elem()),
+		I.Type("ReaderFrom", reflect.TypeOf((*io.ReaderFrom)(nil)).Elem()),
+		I.Type("RuneReader", reflect.TypeOf((*io.RuneReader)(nil)).Elem()),
+		I.Type("RuneScanner", reflect.TypeOf((*io.RuneScanner)(nil)).Elem()),
+		I.Type("SectionReader", reflect.TypeOf((*io.SectionReader)(nil)).Elem()),
+		I.Type("Seeker", reflect.TypeOf((*io.Seeker)(nil)).Elem()),
+		I.Type("StringWriter", reflect.TypeOf((*io.StringWriter)(nil)).Elem()),
+		I.Type("WriteCloser", reflect.TypeOf((*io.WriteCloser)(nil)).Elem()),
+		I.Type("WriteSeeker", reflect.TypeOf((*io.WriteSeeker)(nil)).Elem()),
+		I.Type("Writer", reflect.TypeOf((*io.Writer)(nil)).Elem()),
+		I.Type("WriterAt", reflect.TypeOf((*io.WriterAt)(nil)).Elem()),
+		I.Type("WriterTo", reflect.TypeOf((*io.WriterTo)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("SeekCurrent", qspec.ConstUnboundInt, io.SeekCurrent),
 		I.Const("SeekEnd", qspec.ConstUnboundInt, io.SeekEnd),
diff --git a/lib/log/gomod_export.go b/lib/log/gomod_export.go
index 63553de1..6d60368b 100644
--- a/lib/log/gomod_export.go
+++ b/lib/log/gomod_export.go
@@ -4,6 +4,7 @@ package log
 import (
 	io "io"
 	log "log"
+	reflect "reflect"
 
 	gop "github.com/goplus/gop"
 	qspec "github.com/goplus/gop/exec.spec"
@@ -252,6 +253,9 @@ func init() {
 		I.Funcv("Printf", log.Printf, execPrintf),
 		I.Funcv("Println", log.Println, execPrintln),
 	)
+	I.RegisterTypes(
+		I.Type("Logger", reflect.TypeOf((*log.Logger)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("LUTC", qspec.ConstUnboundInt, log.LUTC),
 		I.Const("Ldate", qspec.ConstUnboundInt, log.Ldate),
diff --git a/lib/os/gomod_export.go b/lib/os/gomod_export.go
index 91ba1e28..8d48e519 100644
--- a/lib/os/gomod_export.go
+++ b/lib/os/gomod_export.go
@@ -3,6 +3,7 @@ package os
 
 import (
 	os "os"
+	reflect "reflect"
 	time "time"
 
 	gop "github.com/goplus/gop"
@@ -732,6 +733,18 @@ func init() {
 		I.Var("Stdin", &os.Stdin),
 		I.Var("Stdout", &os.Stdout),
 	)
+	I.RegisterTypes(
+		I.Type("File", reflect.TypeOf((*os.File)(nil)).Elem()),
+		I.Type("FileInfo", reflect.TypeOf((*os.FileInfo)(nil)).Elem()),
+		I.Type("FileMode", reflect.TypeOf((*os.FileMode)(nil)).Elem()),
+		I.Type("LinkError", reflect.TypeOf((*os.LinkError)(nil)).Elem()),
+		I.Type("PathError", reflect.TypeOf((*os.PathError)(nil)).Elem()),
+		I.Type("ProcAttr", reflect.TypeOf((*os.ProcAttr)(nil)).Elem()),
+		I.Type("Process", reflect.TypeOf((*os.Process)(nil)).Elem()),
+		I.Type("ProcessState", reflect.TypeOf((*os.ProcessState)(nil)).Elem()),
+		I.Type("Signal", reflect.TypeOf((*os.Signal)(nil)).Elem()),
+		I.Type("SyscallError", reflect.TypeOf((*os.SyscallError)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("DevNull", qspec.ConstBoundString, os.DevNull),
 		I.Const("ModeAppend", qspec.Uint32, os.ModeAppend),
diff --git a/lib/reflect/gomod_export.go b/lib/reflect/gomod_export.go
index 446c744b..6ab0ef26 100644
--- a/lib/reflect/gomod_export.go
+++ b/lib/reflect/gomod_export.go
@@ -683,6 +683,21 @@ func init() {
 	I.RegisterFuncvs(
 		I.Funcv("Append", reflect.Append, execAppend),
 	)
+	I.RegisterTypes(
+		I.Type("ChanDir", reflect.TypeOf((*reflect.ChanDir)(nil)).Elem()),
+		I.Type("Kind", reflect.TypeOf((*reflect.Kind)(nil)).Elem()),
+		I.Type("MapIter", reflect.TypeOf((*reflect.MapIter)(nil)).Elem()),
+		I.Type("Method", reflect.TypeOf((*reflect.Method)(nil)).Elem()),
+		I.Type("SelectCase", reflect.TypeOf((*reflect.SelectCase)(nil)).Elem()),
+		I.Type("SelectDir", reflect.TypeOf((*reflect.SelectDir)(nil)).Elem()),
+		I.Type("SliceHeader", reflect.TypeOf((*reflect.SliceHeader)(nil)).Elem()),
+		I.Type("StringHeader", reflect.TypeOf((*reflect.StringHeader)(nil)).Elem()),
+		I.Type("StructField", reflect.TypeOf((*reflect.StructField)(nil)).Elem()),
+		I.Type("StructTag", reflect.TypeOf((*reflect.StructTag)(nil)).Elem()),
+		I.Type("Type", reflect.TypeOf((*reflect.Type)(nil)).Elem()),
+		I.Type("Value", reflect.TypeOf((*reflect.Value)(nil)).Elem()),
+		I.Type("ValueError", reflect.TypeOf((*reflect.ValueError)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("Array", qspec.Uint, reflect.Array),
 		I.Const("Bool", qspec.Uint, reflect.Bool),
diff --git a/lib/strconv/gomod_export.go b/lib/strconv/gomod_export.go
index 8f9bcf7d..bb6d037c 100644
--- a/lib/strconv/gomod_export.go
+++ b/lib/strconv/gomod_export.go
@@ -2,6 +2,7 @@
 package strconv
 
 import (
+	reflect "reflect"
 	strconv "strconv"
 
 	gop "github.com/goplus/gop"
@@ -249,6 +250,9 @@ func init() {
 		I.Var("ErrRange", &strconv.ErrRange),
 		I.Var("ErrSyntax", &strconv.ErrSyntax),
 	)
+	I.RegisterTypes(
+		I.Type("NumError", reflect.TypeOf((*strconv.NumError)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("IntSize", qspec.ConstUnboundInt, strconv.IntSize),
 	)
diff --git a/lib/strings/gomod_export.go b/lib/strings/gomod_export.go
index a4aad757..3b9eb5d4 100644
--- a/lib/strings/gomod_export.go
+++ b/lib/strings/gomod_export.go
@@ -3,6 +3,7 @@ package strings
 
 import (
 	io "io"
+	reflect "reflect"
 	strings "strings"
 	unicode "unicode"
 
@@ -507,4 +508,9 @@ func init() {
 	I.RegisterFuncvs(
 		I.Funcv("NewReplacer", strings.NewReplacer, execNewReplacer),
 	)
+	I.RegisterTypes(
+		I.Type("Builder", reflect.TypeOf((*strings.Builder)(nil)).Elem()),
+		I.Type("Reader", reflect.TypeOf((*strings.Reader)(nil)).Elem()),
+		I.Type("Replacer", reflect.TypeOf((*strings.Replacer)(nil)).Elem()),
+	)
 }
diff --git a/lib/sync/atomic/gomod_export.go b/lib/sync/atomic/gomod_export.go
index a0079651..1e7436d4 100644
--- a/lib/sync/atomic/gomod_export.go
+++ b/lib/sync/atomic/gomod_export.go
@@ -2,6 +2,7 @@
 package atomic
 
 import (
+	reflect "reflect"
 	atomic "sync/atomic"
 	unsafe "unsafe"
 
@@ -231,4 +232,7 @@ func init() {
 		I.Func("(*Value).Load", (*atomic.Value).Load, execmValueLoad),
 		I.Func("(*Value).Store", (*atomic.Value).Store, execmValueStore),
 	)
+	I.RegisterTypes(
+		I.Type("Value", reflect.TypeOf((*atomic.Value)(nil)).Elem()),
+	)
 }
diff --git a/lib/sync/gomod_export.go b/lib/sync/gomod_export.go
index e540b6cf..3eca9ed1 100644
--- a/lib/sync/gomod_export.go
+++ b/lib/sync/gomod_export.go
@@ -2,6 +2,7 @@
 package sync
 
 import (
+	reflect "reflect"
 	sync "sync"
 
 	gop "github.com/goplus/gop"
@@ -174,4 +175,14 @@ func init() {
 		I.Func("(*WaitGroup).Done", (*sync.WaitGroup).Done, execmWaitGroupDone),
 		I.Func("(*WaitGroup).Wait", (*sync.WaitGroup).Wait, execmWaitGroupWait),
 	)
+	I.RegisterTypes(
+		I.Type("Cond", reflect.TypeOf((*sync.Cond)(nil)).Elem()),
+		I.Type("Locker", reflect.TypeOf((*sync.Locker)(nil)).Elem()),
+		I.Type("Map", reflect.TypeOf((*sync.Map)(nil)).Elem()),
+		I.Type("Mutex", reflect.TypeOf((*sync.Mutex)(nil)).Elem()),
+		I.Type("Once", reflect.TypeOf((*sync.Once)(nil)).Elem()),
+		I.Type("Pool", reflect.TypeOf((*sync.Pool)(nil)).Elem()),
+		I.Type("RWMutex", reflect.TypeOf((*sync.RWMutex)(nil)).Elem()),
+		I.Type("WaitGroup", reflect.TypeOf((*sync.WaitGroup)(nil)).Elem()),
+	)
 }
diff --git a/lib/time/gomod_export.go b/lib/time/gomod_export.go
index a6cc61bb..beac25fb 100644
--- a/lib/time/gomod_export.go
+++ b/lib/time/gomod_export.go
@@ -2,6 +2,7 @@
 package time
 
 import (
+	reflect "reflect"
 	time "time"
 
 	gop "github.com/goplus/gop"
@@ -521,6 +522,16 @@ func init() {
 		I.Var("Local", &time.Local),
 		I.Var("UTC", &time.UTC),
 	)
+	I.RegisterTypes(
+		I.Type("Duration", reflect.TypeOf((*time.Duration)(nil)).Elem()),
+		I.Type("Location", reflect.TypeOf((*time.Location)(nil)).Elem()),
+		I.Type("Month", reflect.TypeOf((*time.Month)(nil)).Elem()),
+		I.Type("ParseError", reflect.TypeOf((*time.ParseError)(nil)).Elem()),
+		I.Type("Ticker", reflect.TypeOf((*time.Ticker)(nil)).Elem()),
+		I.Type("Time", reflect.TypeOf((*time.Time)(nil)).Elem()),
+		I.Type("Timer", reflect.TypeOf((*time.Timer)(nil)).Elem()),
+		I.Type("Weekday", reflect.TypeOf((*time.Weekday)(nil)).Elem()),
+	)
 	I.RegisterConsts(
 		I.Const("ANSIC", qspec.ConstBoundString, time.ANSIC),
 		I.Const("April", qspec.Int, time.April),


Test patch:
diff --git a/cl/gopkg_test.go b/cl/gopkg_test.go
index 320ec3a8..d22cdf3b 100644
--- a/cl/gopkg_test.go
+++ b/cl/gopkg_test.go
@@ -698,6 +698,73 @@ import (
 	}
 }
 
+func TestPkgType(t *testing.T) {
+	var I = exec.NewGoPackage("pkg_test_type")
+	I.RegisterTypes(
+		I.Type("Rect", reflect.TypeOf((*trect)(nil)).Elem()),
+		I.Type("Point", reflect.TypeOf((*tpoint)(nil)).Elem()),
+	)
+
+	var testSource = `
+	import pkg "pkg_test_type"
+
+	pkg.Rect{pkg.Point{1,2},pkg.Point{3,4}}
+	pkg.Rect{pkg.Point{X:5,Y:6},pkg.Point{X:7,Y:8}}
+	&pkg.Rect{pkg.Point{1,2},pkg.Point{3,4}}
+	&pkg.Rect{pkg.Point{X:5,Y:6},pkg.Point{X:7,Y:8}}
+	pkg.Point{1,2}
+	pkg.Point{X:3,Y:4}
+	&pkg.Point{5,6}
+	&pkg.Point{X:7,Y:8}
+	`
+
+	fsTestPkgVar := asttest.NewSingleFileFS("/foo", "bar.gop", testSource)
+	t.Log(testSource)
+
+	fset := token.NewFileSet()
+	pkgs, err := parser.ParseFSDir(fset, fsTestPkgVar, "/foo", nil, 0)
+	if err != nil || len(pkgs) != 1 {
+		t.Fatal("ParseFSDir failed:", err, len(pkgs))
+	}
+
+	bar := pkgs["main"]
+	b := exec.NewBuilder(nil)
+	_, _, err = newPackage(b, bar, fset)
+	if err != nil {
+		t.Fatal("Compile failed:", err)
+	}
+	code := b.Resolve()
+	code.Dump(os.Stdout)
+
+	ctx := exec.NewContext(code)
+	ctx.Exec(0, code.Len())
+	if v := ctx.Get(-8); v != nil && !reflect.DeepEqual(v, tMakeRect(1, 2, 3, 4)) {
+		t.Fatal("check rect", v)
+	}
+	if v := ctx.Get(-7); v != nil && !reflect.DeepEqual(v, tMakeRect(5, 6, 7, 8)) {
+		t.Fatal("check rect", v)
+	}
+	if v := ctx.Get(-6); v != nil && !reflect.DeepEqual(v, tNewRect(1, 2, 3, 4)) {
+		t.Fatal("check rect", v)
+	}
+	if v := ctx.Get(-5); v != nil && !reflect.DeepEqual(v, tNewRect(5, 6, 7, 8)) {
+		t.Fatal("check rect", v)
+	}
+	if v := ctx.Get(-4); v != nil && !reflect.DeepEqual(v, tpoint{1, 2}) {
+		t.Fatal("check point", v)
+	}
+	if v := ctx.Get(-3); v != nil && !reflect.DeepEqual(v, tpoint{X: 3, Y: 4}) {
+		t.Fatal("check point", v)
+	}
+	if v := ctx.Get(-2); v != nil && !reflect.DeepEqual(v, &tpoint{5, 6}) {
+		t.Fatal("check point", v)
+	}
+	if v := ctx.Get(-1); v != nil && !reflect.DeepEqual(v, &tpoint{X: 7, Y: 8}) {
+		t.Fatal("check point", v)
+	}
+
+}
+
 func TestPkgTakeAddr(t *testing.T) {
 	var I = exec.NewGoPackage("pkg_test_takeaddr")
 	rc := tMakeRect(10, 20, 100, 200)