From 2d1af6b74559d665b9a67aca5789c6d5b25e065e Mon Sep 17 00:00:00 2001
From: xushiwei <x@goplus.org>
Date: Thu, 7 Nov 2024 15:31:10 +0800
Subject: [PATCH 1/3] cb.ValWithUnit

---
 codebuild.go | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/codebuild.go b/codebuild.go
index 79cbe94..8ac29d2 100644
--- a/codebuild.go
+++ b/codebuild.go
@@ -26,6 +26,7 @@ import (
 	"strconv"
 	"strings"
 	"syscall"
+	"time"
 
 	"github.com/goplus/gogen/internal"
 	xtoken "github.com/goplus/gogen/token"
@@ -1382,6 +1383,44 @@ func (p *CodeBuilder) pushVal(v interface{}, src ast.Node) *CodeBuilder {
 	return p
 }
 
+// ValWithUnit func
+func (p *CodeBuilder) ValWithUnit(v *ast.BasicLit, t types.Type, unit string) *CodeBuilder {
+	if debugInstr {
+		log.Println("ValWithUnit", v.Value, t, unit)
+	}
+	named, ok := t.(*types.Named)
+	if !ok {
+		panic("TODO: ValWithUnit: t isn't a named type")
+	}
+	o := named.Obj()
+	e := toExpr(p.pkg, v, v)
+	if o.Pkg().Path() == "time" && o.Name() == "Duration" { // time.Duration
+		u, ok := timeDurationUnits[unit]
+		if !ok {
+			panic("TODO: ValWithUnit: unknown unit of time.Duration - " + unit)
+		}
+		val := constant.BinaryOp(e.CVal, token.MUL, constant.MakeInt64(int64(u)))
+		e.CVal = val
+		e.Val = &ast.BasicLit{Kind: token.INT, Value: val.ExactString()}
+		e.Type = t
+		p.Val(e, v)
+	} else {
+		panic("TODO: notimpl")
+	}
+	return p
+}
+
+var timeDurationUnits = map[string]time.Duration{
+	"ns": time.Nanosecond,
+	"us": time.Microsecond,
+	"µs": time.Microsecond,
+	"ms": time.Millisecond,
+	"s":  time.Second,
+	"m":  time.Minute,
+	"h":  time.Hour,
+	"d":  24 * time.Hour,
+}
+
 // Star func
 func (p *CodeBuilder) Star(src ...ast.Node) *CodeBuilder {
 	if debugInstr {

From 84b0690ea8631cb349b7a25b57e7c22610b1426c Mon Sep 17 00:00:00 2001
From: xushiwei <x@goplus.org>
Date: Thu, 7 Nov 2024 15:48:02 +0800
Subject: [PATCH 2/3] TestValWithUnit

---
 builtin_test.go | 25 +++++++++++++++++++++++++
 codebuild.go    |  4 ++--
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/builtin_test.go b/builtin_test.go
index 797dbf9..5d2aa6f 100644
--- a/builtin_test.go
+++ b/builtin_test.go
@@ -44,6 +44,31 @@ func getConf() *Config {
 	return &Config{Fset: fset, Importer: imp}
 }
 
+func TestValWithUnit(t *testing.T) {
+	pkg := NewPackage("", "foo", nil)
+	cb := pkg.CB()
+	testValWithUnitPanic(t, "no unit for int", cb, types.Typ[types.Int], "m")
+	testValWithUnitPanic(t, "y is not unit of time.Duration", cb, namedType("time", "Duration"), "y")
+	testValWithUnitPanic(t, "user defined type: not impl", cb, namedType("foo", "Bar"), "m")
+	cb.ValWithUnit(&ast.BasicLit{Value: "1", Kind: token.INT}, namedType("time", "Duration"), "m")
+}
+
+func namedType(pkgName, tName string) types.Type {
+	pkg := types.NewPackage(pkgName, "")
+	return types.NewNamed(types.NewTypeName(0, pkg, tName, nil), types.Typ[types.Int64], nil)
+}
+
+func testValWithUnitPanic(t *testing.T, name string, cb *CodeBuilder, typ types.Type, unit string) {
+	t.Run(name, func(t *testing.T) {
+		defer func() {
+			if e := recover(); e == nil {
+				t.Fatal("TestErrValWithUnit: no panic?")
+			}
+		}()
+		cb.ValWithUnit(&ast.BasicLit{Value: "1", Kind: token.INT}, typ, unit)
+	})
+}
+
 func TestSwitchStmtThen(t *testing.T) {
 	pkg := NewPackage("", "foo", nil)
 	cb := pkg.CB()
diff --git a/codebuild.go b/codebuild.go
index 8ac29d2..8d7be02 100644
--- a/codebuild.go
+++ b/codebuild.go
@@ -1392,9 +1392,9 @@ func (p *CodeBuilder) ValWithUnit(v *ast.BasicLit, t types.Type, unit string) *C
 	if !ok {
 		panic("TODO: ValWithUnit: t isn't a named type")
 	}
-	o := named.Obj()
 	e := toExpr(p.pkg, v, v)
-	if o.Pkg().Path() == "time" && o.Name() == "Duration" { // time.Duration
+	o := named.Obj()
+	if o.Name() == "Duration" && o.Pkg().Path() == "time" { // time.Duration
 		u, ok := timeDurationUnits[unit]
 		if !ok {
 			panic("TODO: ValWithUnit: unknown unit of time.Duration - " + unit)

From 1605e44d181315d6cc020730f84738d415670d07 Mon Sep 17 00:00:00 2001
From: xushiwei <x@goplus.org>
Date: Thu, 7 Nov 2024 15:50:56 +0800
Subject: [PATCH 3/3] t.Helper

---
 builtin_test.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin_test.go b/builtin_test.go
index 5d2aa6f..f97fb56 100644
--- a/builtin_test.go
+++ b/builtin_test.go
@@ -59,6 +59,7 @@ func namedType(pkgName, tName string) types.Type {
 }
 
 func testValWithUnitPanic(t *testing.T, name string, cb *CodeBuilder, typ types.Type, unit string) {
+	t.Helper()
 	t.Run(name, func(t *testing.T) {
 		defer func() {
 			if e := recover(); e == nil {