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

Introduce stringer #3594

Open
wants to merge 13 commits into
base: feature/string-templates
Choose a base branch
from

Conversation

RZhang05
Copy link
Contributor

@RZhang05 RZhang05 commented Sep 26, 2024

Working towards #3579

Description

A simple Stringer struct interface. It is intended in the future that all types which implement Stringer can be used in string templates.


  • Targeted PR against feature/string-templates branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work
  • Code follows the standards mentioned here
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

@SupunS SupunS self-assigned this Oct 1, 2024
@SupunS
Copy link
Member

SupunS commented Oct 1, 2024

@RZhang05 is this ready to be reviewed? or are there any pending changes?

@RZhang05 RZhang05 marked this pull request as ready for review October 1, 2024 22:32
@RZhang05
Copy link
Contributor Author

RZhang05 commented Oct 1, 2024

@RZhang05 is this ready to be reviewed? or are there any pending changes?

It is ready, note that there are some questions left in the code marked with TODO however.

runtime/sema/stringer.go Outdated Show resolved Hide resolved
runtime/sema/type.go Outdated Show resolved Hide resolved
runtime/tests/interpreter/stringer_test.go Outdated Show resolved Hide resolved
runtime/tests/interpreter/stringer_test.go Outdated Show resolved Hide resolved
runtime/tests/interpreter/stringer_test.go Outdated Show resolved Hide resolved
Copy link
Member

@turbolent turbolent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

runtime/sema/type.go Outdated Show resolved Hide resolved
Comment on lines 7840 to 7841
// STRINGERTODO: other options? how to make existing simple types
// conform to an intersection type?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't so much about conforming these types to an intersection type, but an interface, Stringer.

At the moment we don't have a means to specify a subtype relationship for simple types, so we might want to add that, i.e. generalize this solution a bit.

Note that the intersection type might contain multiple interfaces, e.g. might not just be {Stringer}, so checking the first element is not sufficient.

There's also no need, and it is not sufficient, to compare the names only, it is better to check for pointer equality here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment we don't have a means to specify a subtype relationship for simple types, so we might want to add that, i.e. generalize this solution a bit.

In 5f16333, I added the functionality for simple types to conform to an interface.

Not sure the best approach in general for all string convertible types to conform to Stringer since there are types such as TheAddressType and NumberType which are not SimpleTypes so I've left the edge case check in for those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a ConformingType interface as suggested by #3594 (comment).

Comment on lines 9563 to 9584
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)
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to refactor this into a function, and also use it in the init block initializing NativeCompositeTypes

"github.com/onflow/cadence/runtime/common"
)

const StringerTypeName = "Stringer"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we cannot define a single interface that users could implement for both structs and resources. To begin with we're only adding a struct interface, but we might also want to provide another resource interface in the future. We might want to consider naming this so it indicates that it is only for structs, e.g. StructStringer

@RZhang05 RZhang05 changed the base branch from master to feature/string-templates October 2, 2024 15:17
Copy link
Member

@turbolent turbolent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

@@ -164,6 +164,9 @@ type typeDecl struct {
memberDeclarations []ast.Declaration
nestedTypes []*typeDecl
hasConstructor bool

// used in simpleType generation
conformances []string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider making this more type-safe by using a []common.TypeID instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to an InterfaceType for simplicity

common.CompositeKindContract:
break
default:
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
panic(fmt.Sprintf("%s interface declarations are not supported", compositeKind.Name()))

@@ -736,8 +741,151 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
return
}

func (*generator) VisitInterfaceDeclaration(_ *ast.InterfaceDeclaration) struct{} {
panic("interface declarations are not supported")
func (g *generator) VisitInterfaceDeclaration(decl *ast.InterfaceDeclaration) (_ struct{}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything significantly different from VisitCompositeDeclaration? If the code generation is pretty much the same, maybe refactor it into a common function

@@ -1591,6 +1739,9 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr {
// Comparable: false,
// Exportable: false,
// Importable: false,
// comformances: []*InterfaceType {
// StructStringer,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// StructStringer,
// StructStringerType,

@@ -2069,6 +2240,100 @@ func compositeTypeLiteral(ty *typeDecl) dst.Expr {
}
}

func interfaceTypeExpr(ty *typeDecl) dst.Expr {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: Is there anything significantly different from the composite-related functions (compositeTypeExpr, compositeTypeLiteral)? If the code generation is pretty much the same, maybe refactor it into a common function

@@ -7244,11 +7276,18 @@ const AddressTypeName = "Address"

// AddressType represents the address type
type AddressType struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above for NumericType

Comment on lines 9575 to 9580
nestedCompositeType, ok := nestedType.(*CompositeType)
if !ok {
return
}

types = append(types, nestedCompositeType)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add all nested types (e.g. interface types), not just composite types

Suggested change
nestedCompositeType, ok := nestedType.(*CompositeType)
if !ok {
return
}
types = append(types, nestedCompositeType)
types = append(types, nestedType)

Comment on lines 9591 to 9596
nestedInterfaceType, ok := nestedType.(*InterfaceType)
if !ok {
return
}

types = append(types, nestedInterfaceType)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Suggested change
nestedInterfaceType, ok := nestedType.(*InterfaceType)
if !ok {
return
}
types = append(types, nestedInterfaceType)
types = append(types, nestedType)

types = append(types, nestedInterfaceType)
})
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a default case and panic(errors.NewUnreachableError())

@@ -736,8 +741,151 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
return
}

func (*generator) VisitInterfaceDeclaration(_ *ast.InterfaceDeclaration) struct{} {
panic("interface declarations are not supported")
func (g *generator) VisitInterfaceDeclaration(decl *ast.InterfaceDeclaration) (_ struct{}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case to sema/gen/testdata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants