diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index a99f854410..b1576c1216 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -4866,6 +4866,10 @@ func (interpreter *Interpreter) GetInterfaceType( typeID TypeID, ) (*sema.InterfaceType, error) { if location == nil { + var interfaceType = sema.NativeInterfaceTypes[qualifiedIdentifier] + if interfaceType != nil { + return interfaceType, nil + } return nil, InterfaceMissingLocationError{ QualifiedIdentifier: qualifiedIdentifier, } diff --git a/runtime/sema/stringer.go b/runtime/sema/stringer.go index 67fef4abaf..1331fdc3eb 100644 --- a/runtime/sema/stringer.go +++ b/runtime/sema/stringer.go @@ -23,43 +23,37 @@ import ( "github.com/onflow/cadence/runtime/common" ) -const StringerTypeToStringFunctionName = "toString" +const StringerTypeName = "Stringer" -var StringerTypeToStringFunctionType = &FunctionType{ - Purity: FunctionPurityView, - ReturnTypeAnnotation: NewTypeAnnotation( - StringType, - ), -} +var StringerType = func() *InterfaceType { -const StringerTypeToStringFunctionDocString = ` - Returns this object as a String. - ` + stringerType := &InterfaceType{ + Identifier: StringerTypeName, + CompositeKind: common.CompositeKindStructure, + Members: &StringMemberOrderedMap{}, + } -const StringerTypeName = "Stringer" + const StringerTypeToStringFunctionDocString = `Returns this object as a String.` -var StringerType = InterfaceType{ - Location: nil, - Identifier: StringerTypeName, - CompositeKind: common.CompositeKindStructure, - Members: &StringMemberOrderedMap{}, -} + const StringerTypeToStringFunctionName = "toString" -func init() { - StringerType.Members.Set(StringerTypeToStringFunctionName, NewUnmeteredFunctionMember( - &StringerType, - PrimitiveAccess(ast.AccessAll), - StringerTypeToStringFunctionName, - StringerTypeToStringFunctionType, - StringerTypeToStringFunctionDocString, - )) - StringerType.memberResolvers = MembersAsResolvers([]*Member{ + var StringerTypeToStringFunctionType = &FunctionType{ + Purity: FunctionPurityView, + ReturnTypeAnnotation: NewTypeAnnotation( + StringType, + ), + } + + var members = []*Member{ NewUnmeteredFunctionMember( - &StringerType, + stringerType, PrimitiveAccess(ast.AccessAll), StringerTypeToStringFunctionName, StringerTypeToStringFunctionType, StringerTypeToStringFunctionDocString, ), - }) -} + } + + stringerType.Members = MembersAsMap(members) + return stringerType +}() diff --git a/runtime/sema/type.go b/runtime/sema/type.go index f659ccf4ac..c9ab715c7f 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4198,7 +4198,7 @@ func init() { DeploymentResultType, HashableStructType, &InclusiveRangeType{}, - &StringerType, + StringerType, }, ) @@ -9552,3 +9552,34 @@ func init() { }) } } + +var NativeInterfaceTypes = map[string]*InterfaceType{} + +func init() { + interfaceTypes := []*InterfaceType{ + StringerType, + } + + for len(interfaceTypes) > 0 { + lastIndex := len(interfaceTypes) - 1 + interfaceType := interfaceTypes[lastIndex] + interfaceTypes[lastIndex] = nil + interfaceTypes = interfaceTypes[:lastIndex] + + NativeInterfaceTypes[interfaceType.QualifiedIdentifier()] = interfaceType + + nestedTypes := interfaceType.NestedTypes + if nestedTypes == nil { + continue + } + + nestedTypes.Foreach(func(_ string, nestedType Type) { + nestedInterfaceType, ok := nestedType.(*InterfaceType) + if !ok { + return + } + + interfaceTypes = append(interfaceTypes, nestedInterfaceType) + }) + } +} diff --git a/runtime/sema/type_test.go b/runtime/sema/type_test.go index 0f0bcf40cf..ebaca4f36b 100644 --- a/runtime/sema/type_test.go +++ b/runtime/sema/type_test.go @@ -2378,6 +2378,10 @@ func TestTypeInclusions(t *testing.T) { return } + if _, ok := typ.(*InterfaceType); ok { + return + } + if typ.IsResourceType() { return } diff --git a/runtime/tests/interpreter/stringer_test.go b/runtime/tests/interpreter/stringer_test.go index 2ebf40cabd..fbd6da1388 100644 --- a/runtime/tests/interpreter/stringer_test.go +++ b/runtime/tests/interpreter/stringer_test.go @@ -21,9 +21,10 @@ package interpreter_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime/interpreter" . "github.com/onflow/cadence/runtime/tests/utils" - "github.com/stretchr/testify/require" ) func TestStringerBasic(t *testing.T) { @@ -52,3 +53,26 @@ func TestStringerBasic(t *testing.T) { result, ) } + +func TestStringerBuiltIn(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + access(all) + fun test() :String { + let v = 1 + return v.toString() + } + `) + + result, err := inter.Invoke("test") + require.NoError(t, err) + + RequireValuesEqual( + t, + inter, + interpreter.NewUnmeteredStringValue("1"), + result, + ) +}