Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions interpreter/struct_stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package interpreter_test

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -101,6 +102,84 @@ func TestStringerCast(t *testing.T) {
)
}

func TestStringerFixedPointAndAddress(t *testing.T) {

t.Parallel()

runTest := func(t *testing.T, code, expected string) {
inter := parseCheckAndPrepare(t, code)

result, err := inter.Invoke("test")
require.NoError(t, err)

RequireValuesEqual(
t,
inter,
interpreter.NewUnmeteredStringValue(expected),
result,
)
}

// Static cast to `{StructStringer}`, then call `toString`.
t.Run("static cast", func(t *testing.T) {
t.Parallel()

for _, test := range []struct {
value string
expected string
}{
{"1.0 as Fix64", "1.00000000"},
{"1.0 as UFix64", "1.00000000"},
{"1.0 as Fix128", "1.000000000000000000000000"},
{"1.0 as UFix128", "1.000000000000000000000000"},
{"0x1 as Address", "0x0000000000000001"},
} {
value, expected := test.value, test.expected
t.Run(value, func(t *testing.T) {
t.Parallel()

runTest(t, fmt.Sprintf(`
access(all)
fun test(): String {
let v = %s as {StructStringer}
return v.toString()
}
`, value), expected)
})
}
})

// Runtime cast (`as?`) to `{StructStringer}`, then call `toString`.
t.Run("runtime cast", func(t *testing.T) {
t.Parallel()

for _, test := range []struct {
value string
expected string
}{
{"1.0 as Fix64", "1.00000000"},
{"1.0 as UFix64", "1.00000000"},
{"1.0 as Fix128", "1.000000000000000000000000"},
{"1.0 as UFix128", "1.000000000000000000000000"},
{"0x1 as Address", "0x0000000000000001"},
} {
value, expected := test.value, test.expected
t.Run(value, func(t *testing.T) {
t.Parallel()

runTest(t, fmt.Sprintf(`
access(all)
fun test(): String {
let v = %s
let s = (v as AnyStruct) as? {StructStringer}
return s!.toString()
}
`, value), expected)
})
}
})
}

func TestStringerAsValue(t *testing.T) {

t.Parallel()
Expand Down
7 changes: 6 additions & 1 deletion sema/struct_stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,19 @@ func TestCheckStringer(t *testing.T) {
let a: {StructStringer} = 1
let b: {StructStringer} = false
let c: {StructStringer} = "hey"
access(all)
access(all)
struct Foo: StructStringer {
view fun toString(): String {
return "foo"
}
}
let d: {StructStringer} = Foo()
let e: {StructStringer} = /public/foo
let f: {StructStringer} = 1.0 as Fix64
let g: {StructStringer} = 1.0 as UFix64
let h: {StructStringer} = 1.0 as Fix128
let i: {StructStringer} = 1.0 as UFix128
let j: {StructStringer} = 0x1 as Address
`)

assert.NoError(t, err)
Expand Down
54 changes: 51 additions & 3 deletions sema/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,7 @@ type FixedPointNumericType struct {
}

var _ Type = &FixedPointNumericType{}
var _ ConformingType = &FixedPointNumericType{}
var _ IntegerRangedType = &FixedPointNumericType{}
var _ FractionalRangedType = &FixedPointNumericType{}
var _ SaturatingArithmeticType = &FixedPointNumericType{}
Expand Down Expand Up @@ -1968,6 +1969,34 @@ func (*FixedPointNumericType) CheckInstantiated(
// NO-OP
}

var fixedPointNumericTypeEffectiveInterfaceConformanceSet *InterfaceSet
var fixedPointNumericTypeEffectiveInterfaceConformances []Conformance

func init() {
fixedPointNumericTypeInterfaces := []*InterfaceType{
StructStringerType,
}

fixedPointNumericTypeEffectiveInterfaceConformanceSet = NewInterfaceSet()
for _, interfaceType := range fixedPointNumericTypeInterfaces {
fixedPointNumericTypeEffectiveInterfaceConformanceSet.Add(interfaceType)
}

fixedPointNumericTypeEffectiveInterfaceConformances = distinctConformances(
fixedPointNumericTypeInterfaces,
nil,
map[*InterfaceType]struct{}{},
)
}

func (t *FixedPointNumericType) EffectiveInterfaceConformanceSet() *InterfaceSet {
return fixedPointNumericTypeEffectiveInterfaceConformanceSet
}

func (t *FixedPointNumericType) EffectiveInterfaceConformances() []Conformance {
return fixedPointNumericTypeEffectiveInterfaceConformances
}

// Numeric types

// NumberType represents the super-type of all number types
Expand Down Expand Up @@ -8045,6 +8074,7 @@ var TheAddressType = &AddressType{}
var AddressTypeAnnotation = NewTypeAnnotation(TheAddressType)

var _ Type = &AddressType{}
var _ ConformingType = &AddressType{}
var _ IntegerRangedType = &AddressType{}

func (*AddressType) IsType() {}
Expand Down Expand Up @@ -8197,13 +8227,31 @@ func (t *AddressType) GetMembers() map[string]MemberResolver {
}

var addressTypeEffectiveInterfaceConformanceSet *InterfaceSet
var addressTypeEffectiveInterfaceConformances []Conformance

func init() {
addressTypeInterfaces := []*InterfaceType{
StructStringerType,
}

addressTypeEffectiveInterfaceConformanceSet = NewInterfaceSet()
addressTypeEffectiveInterfaceConformanceSet.Add(StructStringerType)
for _, interfaceType := range addressTypeInterfaces {
addressTypeEffectiveInterfaceConformanceSet.Add(interfaceType)
}

addressTypeEffectiveInterfaceConformances = distinctConformances(
addressTypeInterfaces,
nil,
map[*InterfaceType]struct{}{},
)
}
func (t *AddressType) AddressInterfaceConformanceSet() *InterfaceSet {
return numericTypeEffectiveInterfaceConformanceSet

func (t *AddressType) EffectiveInterfaceConformanceSet() *InterfaceSet {
return addressTypeEffectiveInterfaceConformanceSet
}

func (t *AddressType) EffectiveInterfaceConformances() []Conformance {
return addressTypeEffectiveInterfaceConformances
}

func IsPrimitiveOrContainerOfPrimitive(referencedType Type) bool {
Expand Down
Loading