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
}
74 changes: 65 additions & 9 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1621,8 +1621,12 @@
lhs0 := n.Lhs[0].(*NameExpr).Name
lhs1 := n.Lhs[1].(*NameExpr).Name

var mt *MapType
dt := evalStaticTypeOf(store, last, cx.X)
mt := baseOf(dt).(*MapType)
mt, ok := baseOf(dt).(*MapType)
if !ok {
panic(fmt.Sprintf("invalid index expression on %T", dt))

Check warning on line 1628 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1628

Added line #L1628 was not covered by tests
}
// re-definitions
last.Define(lhs0, anyValue(mt.Value))
last.Define(lhs1, anyValue(BoolType))
Expand Down Expand Up @@ -2263,12 +2267,12 @@
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 @@ -2465,11 +2469,13 @@
// "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 @@ -2490,11 +2496,61 @@
// 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
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 @@
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 @@
return ""
}

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

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

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

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

Check warning on line 378 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L377-L378

Added lines #L377 - L378 were not covered by tests
}

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

Expand Down Expand Up @@ -528,6 +537,10 @@
return ""
}

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

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

Expand Down Expand Up @@ -574,6 +587,10 @@
return ""
}

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

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

Expand Down Expand Up @@ -612,6 +629,10 @@
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 @@
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 @@
panic("package types has no package path (unlike package values)")
}

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

Check warning on line 896 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L895-L896

Added lines #L895 - L896 were not covered by tests
}

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

Expand Down Expand Up @@ -926,6 +955,10 @@
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 @@
return ""
}

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

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

Expand Down Expand Up @@ -1280,6 +1317,10 @@
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 @@
return ""
}

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

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

Expand Down Expand Up @@ -1366,6 +1411,10 @@
panic("typeval types have no package path")
}

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

Check warning on line 1415 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L1414-L1415

Added lines #L1414 - L1415 were not covered by tests
}

// ----------------------------------------
// Declared type
// Declared types have a name, base (underlying) type,
Expand Down Expand Up @@ -1450,6 +1499,10 @@
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 @@
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 @@
panic("blockType has no package path")
}

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

Check warning on line 1960 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L1959-L1960

Added lines #L1959 - L1960 were not covered by tests
}

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

Expand Down Expand Up @@ -1945,6 +2010,10 @@
panic("typleType has no package path")
}

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

Check warning on line 2014 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L2013-L2014

Added lines #L2013 - L2014 were not covered by tests
}

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

Expand All @@ -1965,11 +2034,15 @@
}

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

Check warning on line 2037 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L2037

Added line #L2037 was not covered by tests
}

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

Check warning on line 2041 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L2041

Added line #L2041 was not covered by tests
}

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

Check warning on line 2045 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L2044-L2045

Added lines #L2044 - L2045 were not covered by tests
}

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

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

Check warning on line 2079 in gnovm/pkg/gnolang/types.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/types.go#L2078-L2079

Added lines #L2078 - L2079 were not covered by tests
}

// ----------------------------------------
// 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 @@ -376,7 +376,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