Repository: goplus/gop
Pull request #1532 (2023-11-08 11:56:01)

cl/internal/typesutil.NewTypeAndValue


Patch:
diff --git a/cl/expr.go b/cl/expr.go
index f3abf968..00d90fe9 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -28,6 +28,7 @@ import (
 	"strings"
 
 	"github.com/goplus/gop/ast"
+	"github.com/goplus/gop/cl/internal/typesutil"
 	"github.com/goplus/gop/printer"
 	"github.com/goplus/gop/token"
 	"github.com/goplus/gox"
@@ -161,7 +162,7 @@ find:
 		}
 		rec.Use(ident, o)
 		typ, _ := gox.DerefType(e.Type)
-		tv := types.TypeAndValue{Type: typ, Value: e.CVal}
+		tv := typesutil.NewTypeAndValue(typ, e.CVal)
 		rec.Type(ident, tv)
 	}
 	return
@@ -360,7 +361,7 @@ func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr) {
 		compileExpr(ctx, v.X)
 		if rec := ctx.recorder(); rec != nil {
 			e := ctx.cb.Get(-1)
-			rec.Type(v.X, types.TypeAndValue{Type: e.Type, Value: e.CVal})
+			rec.Type(v.X, typesutil.NewTypeAndValue(e.Type, e.CVal))
 		}
 	}
 	ctx.cb.MemberRef(v.Sel.Name, v)
@@ -382,7 +383,7 @@ func compileSelectorExpr(ctx *blockCtx, v *ast.SelectorExpr, flags int) {
 		compileExpr(ctx, v.X)
 		if rec := ctx.recorder(); rec != nil {
 			e := ctx.cb.Get(-1)
-			rec.Type(v.X, types.TypeAndValue{Type: e.Type, Value: e.CVal})
+			rec.Type(v.X, typesutil.NewTypeAndValue(e.Type, e.CVal))
 		}
 	}
 	if err := compileMember(ctx, v, v.Sel.Name, flags); err != nil {
diff --git a/cl/internal/typesutil/api.go b/cl/internal/typesutil/api.go
new file mode 100644
index 00000000..e5827a9d
--- /dev/null
+++ b/cl/internal/typesutil/api.go
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typesutil
+
+import (
+	"go/constant"
+	"go/types"
+	"unsafe"
+
+	"github.com/goplus/gox"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+	invalid   operandMode = iota // operand is invalid
+	novalue                      // operand represents no value (result of a function call w/o result)
+	builtin                      // operand is a built-in function
+	typexpr                      // operand is a type
+	constant_                    // operand is a constant; the operand's typ is a Basic type
+	variable                     // operand is an addressable variable
+	mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+	value                        // operand is a computed value
+	commaok                      // like value, but operand may be used in a comma,ok expression
+	commaerr                     // like commaok, but second value is error, not boolean
+	cgofunc                      // operand is a cgo function
+)
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+	mode  operandMode
+	Type  types.Type
+	Value constant.Value
+}
+
+func NewTypeAndValue(typ types.Type, val constant.Value) (ret types.TypeAndValue) {
+	if t, ok := typ.(*gox.TypeType); ok {
+		ret.Type = t.Type()
+		(*TypeAndValue)(unsafe.Pointer(&ret)).mode = typexpr
+	} else {
+		ret.Type = typ
+		ret.Value = val
+	}
+	return
+}
diff --git a/x/typesutil/gopinfo.go b/x/typesutil/gopinfo.go
index e95f8631..b9843279 100644
--- a/x/typesutil/gopinfo.go
+++ b/x/typesutil/gopinfo.go
@@ -185,7 +185,9 @@ func (info gopRecorder) Type(e ast.Expr, tv types.TypeAndValue) {
 	if debugVerbose {
 		log.Println("==> Type:", e, tv.Type)
 	}
-	info.Types[e] = tv
+	if info.Types != nil {
+		info.Types[e] = tv
+	}
 }
 
 // Instantiate maps identifiers denoting generic types or functions to their
@@ -201,7 +203,9 @@ func (info gopRecorder) Type(e ast.Expr, tv types.TypeAndValue) {
 // Invariant: Instantiating Uses[id].Type() with Instances[id].TypeArgs
 // results in an equivalent of Instances[id].Type.
 func (info gopRecorder) Instantiate(id *ast.Ident, inst types.Instance) {
-	info.Instances[id] = inst
+	if info.Instances != nil {
+		info.Instances[id] = inst
+	}
 }
 
 // Def maps identifiers to the objects they define (including
@@ -217,7 +221,9 @@ func (info gopRecorder) Def(id *ast.Ident, obj types.Object) {
 	if debugVerbose {
 		log.Println("==> Def:", id, obj)
 	}
-	info.Defs[id] = obj
+	if info.Defs != nil {
+		info.Defs[id] = obj
+	}
 }
 
 // Use maps identifiers to the objects they denote.
@@ -229,7 +235,9 @@ func (info gopRecorder) Use(id *ast.Ident, obj types.Object) {
 	if debugVerbose {
 		log.Println("==> Use:", id, obj)
 	}
-	info.Uses[id] = obj
+	if info.Uses != nil {
+		info.Uses[id] = obj
+	}
 }
 
 // Implicit maps nodes to their implicitly declared objects, if any.
@@ -244,13 +252,17 @@ func (info gopRecorder) Implicit(node ast.Node, obj types.Object) {
 	if debugVerbose {
 		log.Println("==> Implicit:", obj)
 	}
-	info.Implicits[node] = obj
+	if info.Implicits != nil {
+		info.Implicits[node] = obj
+	}
 }
 
 // Select maps selector expressions (excluding qualified identifiers)
 // to their corresponding selections.
 func (info gopRecorder) Select(e *ast.SelectorExpr, sel *types.Selection) {
-	info.Selections[e] = sel
+	if info.Selections != nil {
+		info.Selections[e] = sel
+	}
 }
 
 // Scope maps ast.Nodes to the scopes they define. Package scopes are not
@@ -280,7 +292,9 @@ func (info gopRecorder) Scope(n ast.Node, scope *types.Scope) {
 	if debugVerbose {
 		log.Println("==> Scope:", scope)
 	}
-	info.Scopes[n] = scope
+	if info.Scopes != nil {
+		info.Scopes[n] = scope
+	}
 }
 
 // -----------------------------------------------------------------------------


Test patch:
diff --git a/cl/internal/typesutil/api_test.go b/cl/internal/typesutil/api_test.go
new file mode 100644
index 00000000..684f2d86
--- /dev/null
+++ b/cl/internal/typesutil/api_test.go
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typesutil
+
+import (
+	"go/constant"
+	"go/types"
+	"testing"
+
+	"github.com/goplus/gox"
+)
+
+func TestTypeAndValue(t *testing.T) {
+	ty := gox.NewTypeType(types.Typ[types.Int])
+	ret := NewTypeAndValue(ty, nil)
+	if !ret.IsType() {
+		t.Fatal("NewTypeAndValue: not type?")
+	}
+	ret = NewTypeAndValue(types.Typ[types.Int], constant.MakeInt64(1))
+	if ret.Value == nil {
+		t.Fatal("NewTypeAndValue: not const?")
+	}
+}