Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: named and unnamed type assignment 2 of 3 #1246

Merged
merged 12 commits into from
May 31, 2024
22 changes: 22 additions & 0 deletions examples/gno.land/r/demo/tests/realm_compositelit.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tests

type (
Word uint
nat []Word
)

var zero = &Int{
neg: true,
abs: []Word{0},
}

// structLit
type Int struct {
neg bool
abs nat
}

func GetZeroType() nat {
a := zero.abs
return a
}
19 changes: 19 additions & 0 deletions examples/gno.land/r/demo/tests/realm_method38d.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package tests

var abs nat

func (n nat) Add() nat {
return []Word{0}
}

func GetAbs() nat {
abs = []Word{0}

return abs
}

func AbsAdd() nat {
rt := GetAbs().Add()

return rt
}
77 changes: 67 additions & 10 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1582,8 +1582,13 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
lhs0 := n.Lhs[0].(*NameExpr).Name
lhs1 := n.Lhs[1].(*NameExpr).Name

dt := evalStaticTypeOf(store, last, cx.X)
mt := baseOf(dt).(*MapType)
var mt *MapType
st := evalStaticTypeOf(store, last, cx.X)
if dt, ok := st.(*DeclaredType); ok {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
mt = dt.Base.(*MapType)
piux2 marked this conversation as resolved.
Show resolved Hide resolved
} else if mt, ok = st.(*MapType); !ok {
panic("invalid index expression on MapType")
}
// re-definitions
last.Define(lhs0, anyValue(mt.Value))
last.Define(lhs1, anyValue(BoolType))
Expand Down Expand Up @@ -2195,12 +2200,12 @@ func getResultTypedValues(cx *CallExpr) []TypedValue {
func evalConst(store Store, last BlockNode, x Expr) *ConstExpr {
// TODO: some check or verification for ensuring x
// is constant? From the machine?
cv := NewMachine(".dontcare", store)
tv := cv.EvalStatic(last, x)
cv.Release()
m := NewMachine(".dontcare", store)
cv := m.EvalStatic(last, x)
m.Release()
cx := &ConstExpr{
Source: x,
TypedValue: tv,
TypedValue: cv,
}
cx.SetAttribute(ATTR_PREPROCESSED, true)
setConstAttrs(cx)
Expand Down Expand Up @@ -2357,11 +2362,13 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
// "push" expected type into shift binary's left operand.
checkOrConvertType(store, last, &bx.Left, t, autoNative)
} else if *x != nil { // XXX if x != nil && t != nil {
// check type
xt := evalStaticTypeOf(store, last, *x)
if t != nil {
checkType(xt, t, autoNative)
}
if isUntyped(xt) {
// convert type
if isUntyped(xt) { // convert if x is untyped literal
if t == nil {
t = defaultTypeOf(xt)
}
Expand All @@ -2382,11 +2389,61 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
// default:
}
}
cx := Expr(Call(constType(nil, t), *x))
cx = Preprocess(store, last, cx).(Expr)
*x = cx
// convert x to destination type t
thehowl marked this conversation as resolved.
Show resolved Hide resolved
convertType(store, last, x, t)
} else {
// if one side is declared name type and the other side is unnamed type
if isNamedConversion(xt, t) {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
// covert right (xt) to the type of the left (t)
convertType(store, last, x, t)
}
}
}
}

// convert x to destination type t
func convertType(store Store, last BlockNode, x *Expr, t Type) {
cx := Expr(Call(constType(nil, t), *x))
cx = Preprocess(store, last, cx).(Expr)
*x = cx
}

// isNamedConversion returns true if assigning a value of type
// xt (rhs) into a value of type t (lhs) entails an implicit type conversion.
// xt is the result of an expression type.
//
// In a few special cases, we should not perform the conversion:
// case 1: the LHS is an interface, which is unnamed, so we should not
// convert to that even if right is a named type.
// case 2: isNamedConversion is called within evaluating make() or new()
// (uverse functions). It returns TypType (generic) which does have IsNamed appropriate

thehowl marked this conversation as resolved.
Show resolved Hide resolved
func isNamedConversion(xt, t Type) bool {
if t == nil {
t = xt
}

// no conversion case 1: the LHS is an interface

_, c1 := t.(*InterfaceType)

// no conversion case2: isNamedConversion is called within evaluating make() or new()
// (uverse functions)

_, oktt := t.(*TypeType)
_, oktt2 := xt.(*TypeType)
c2 := oktt || oktt2

//
if !c1 && !c2 { // carve out above two cases
// covert right to the type of left if one side is unnamed type and the other side is not

if t.IsNamed() && !xt.IsNamed() ||
!t.IsNamed() && xt.IsNamed() {
return true
}
}
return false
}

// like checkOrConvertType(last, x, nil)
Expand Down
81 changes: 79 additions & 2 deletions gnovm/pkg/gnolang/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Type interface {
String() string // for dev/debugging
Elem() Type // for TODO... types
GetPkgPath() string
IsNamed() bool // named vs unname type. property as a method
}

type TypeID string
Expand Down Expand Up @@ -323,6 +324,10 @@ func (pt PrimitiveType) GetPkgPath() string {
return ""
}

func (pt PrimitiveType) IsNamed() bool {
return true
}

// ----------------------------------------
// Field type (partial)

Expand Down Expand Up @@ -369,6 +374,10 @@ func (ft FieldType) GetPkgPath() string {
panic("FieldType is a pseudotype with no package path")
}

func (ft FieldType) IsNamed() bool {
panic("FieldType is a pseudotype with no property called named")
}

// ----------------------------------------
// FieldTypeList

Expand Down Expand Up @@ -528,6 +537,10 @@ func (at *ArrayType) GetPkgPath() string {
return ""
}

func (at *ArrayType) IsNamed() bool {
return false
}

// ----------------------------------------
// Slice type

Expand Down Expand Up @@ -574,6 +587,10 @@ func (st *SliceType) GetPkgPath() string {
return ""
}

func (st *SliceType) IsNamed() bool {
return false
}

// ----------------------------------------
// Pointer type

Expand Down Expand Up @@ -612,6 +629,10 @@ func (pt *PointerType) GetPkgPath() string {
return pt.Elt.GetPkgPath()
}

func (pt *PointerType) IsNamed() bool {
return false
}

func (pt *PointerType) FindEmbeddedFieldType(callerPath string, n Name, m map[Type]struct{}) (
trail []ValuePath, hasPtr bool, rcvr Type, field Type, accessError bool,
) {
Expand Down Expand Up @@ -747,6 +768,10 @@ func (st *StructType) GetPkgPath() string {
return st.PkgPath
}

func (st *StructType) IsNamed() bool {
return false
}

// NOTE only works for exposed non-embedded fields.
func (st *StructType) GetPathForName(n Name) ValuePath {
for i := 0; i < len(st.Fields); i++ {
Expand Down Expand Up @@ -867,6 +892,10 @@ func (pt *PackageType) GetPkgPath() string {
panic("package types has no package path (unlike package values)")
}

func (pt *PackageType) IsNamed() bool {
panic("package types have no property called named")
}

// ----------------------------------------
// Interface type

Expand Down Expand Up @@ -926,6 +955,10 @@ func (it *InterfaceType) GetPkgPath() string {
return it.PkgPath
}

func (it *InterfaceType) IsNamed() bool {
return false
}

func (it *InterfaceType) FindEmbeddedFieldType(callerPath string, n Name, m map[Type]struct{}) (
trail []ValuePath, hasPtr bool, rcvr Type, ft Type, accessError bool,
) {
Expand Down Expand Up @@ -1073,6 +1106,10 @@ func (ct *ChanType) GetPkgPath() string {
return ""
}

func (ct *ChanType) IsNamed() bool {
return false
}

// ----------------------------------------
// Function type

Expand Down Expand Up @@ -1280,6 +1317,10 @@ func (ft *FuncType) GetPkgPath() string {
panic("function types have no package path")
}

func (ft *FuncType) IsNamed() bool {
return false
}

func (ft *FuncType) HasVarg() bool {
if numParams := len(ft.Params); numParams == 0 {
return false
Expand Down Expand Up @@ -1338,6 +1379,10 @@ func (mt *MapType) GetPkgPath() string {
return ""
}

func (mt *MapType) IsNamed() bool {
return false
}

// ----------------------------------------
// Type (typeval) type

Expand Down Expand Up @@ -1366,6 +1411,10 @@ func (tt *TypeType) GetPkgPath() string {
panic("typeval types have no package path")
}

func (tt *TypeType) IsNamed() bool {
panic("typeval types have no property called 'named'")
}

// ----------------------------------------
// Declared type
// Declared types have a name, base (underlying) type,
Expand Down Expand Up @@ -1450,6 +1499,10 @@ func (dt *DeclaredType) GetPkgPath() string {
return dt.PkgPath
}

func (dt *DeclaredType) IsNamed() bool {
return true
}

func (dt *DeclaredType) DefineMethod(fv *FuncValue) {
if !dt.TryDefineMethod(fv) {
panic(fmt.Sprintf("redeclaration of method %s.%s",
Expand Down Expand Up @@ -1767,6 +1820,14 @@ func (nt *NativeType) GetPkgPath() string {
return "go:" + nt.Type.PkgPath()
}

func (nt *NativeType) IsNamed() bool {
if nt.Type.Name() != "" {
return true
} else {
return false
}
thehowl marked this conversation as resolved.
Show resolved Hide resolved
}

func (nt *NativeType) GnoType(store Store) Type {
if nt.gnoType == nil {
nt.gnoType = store.Go2GnoType(nt.Type)
Expand Down Expand Up @@ -1895,6 +1956,10 @@ func (bt blockType) GetPkgPath() string {
panic("blockType has no package path")
}

func (bt blockType) IsNamed() bool {
panic("blockType has no property called named")
}

// ----------------------------------------
// tupleType

Expand Down Expand Up @@ -1945,6 +2010,10 @@ func (tt *tupleType) GetPkgPath() string {
panic("typleType has no package path")
}

func (tt *tupleType) IsNamed() bool {
panic("typleType has no property called named")
}

// ----------------------------------------
// RefType

Expand All @@ -1965,11 +2034,15 @@ func (rt RefType) String() string {
}

func (rt RefType) Elem() Type {
panic("should not happen")
panic("RefType has no elem type")
}

func (rt RefType) GetPkgPath() string {
panic("should not happen")
panic("RefType has no package path")
}

func (rt RefType) IsNamed() bool {
panic("RefType has no property called named")
}

// ----------------------------------------
Expand Down Expand Up @@ -2002,6 +2075,10 @@ func (mn MaybeNativeType) GetPkgPath() string {
return mn.Type.GetPkgPath()
}

func (mn MaybeNativeType) IsNamed() bool {
return mn.Type.IsNamed()
}

// ----------------------------------------
// Kind

Expand Down
4 changes: 2 additions & 2 deletions gnovm/pkg/gnolang/uverse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestIssue1337PrintNilSliceAsUndefined(t *testing.T) {
var a []string
println(a)
}`,
expected: "nil []string\n",
expected: "(nil []string)\n",
},
{
name: "print non-empty slice",
Expand All @@ -57,7 +57,7 @@ func TestIssue1337PrintNilSliceAsUndefined(t *testing.T) {
var a map[string]string
println(a)
}`,
expected: "nil map[string]string\n",
expected: "(nil map[string]string)\n",
},
{
name: "print non-empty map",
Expand Down
2 changes: 1 addition & 1 deletion gnovm/pkg/gnolang/values_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func (tv *TypedValue) ProtectedSprint(seen *seenValues, considerDeclaredType boo
default:
// The remaining types may have a nil value.
if tv.V == nil {
return nilStr + " " + tv.T.String()
return "(" + nilStr + " " + tv.T.String() + ")"
}

// *ArrayType, *SliceType, *StructType, *MapType
Expand Down
Loading
Loading