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): Add support for recursive shapes in Go #608

Merged
merged 97 commits into from
Oct 16, 2024

Conversation

rishav-karanjit
Copy link

@rishav-karanjit rishav-karanjit commented Sep 23, 2024

This PR includes:

  • Support for the recursive shape
  • Formatting the code
  • Adding/updating go.mod in test models
  • New test model (recursive shape)

* Put container shape conv to different function

* Write functions to support recursive shape

* Update aggregate model for test only

* Some refactoring

* Add logic to support recursive function

* Rename recursiveShapeHelper -> toNativeContainerShapeHelper

* Fix changes made for recursive shape

* Some more fixes

* Add my plan --REVERT_LATER

* Fix

* Add go mod to dafny runtime go

* Add go mod to Standard library

* Support recursive shapes in to dafny

* Add toDafnyContainerShapeHelper

* Separate shapes into functions in To dafny

* Comment contraints validation code for now

* Put recursive shape inside aggregate

* Remove adding go mod to deps

* Add }

* Update shape visitor and its helper

* Update DafnyLocalServiceTypeConversionProtocol

* Add a }

* Remove unwanted print

* Remove all unwanted func()

* Function name should be based on member shape not on shape

* Add check for member shape and shape

* Update validation generator for Recursive shape

* Fix validation

* Add list

* Revert "Add list"

This reverts commit 2036bbf.

* Add recursive shape

* Add recussive shape

* revert back

* Add assertionRequired boolean

* Add knownSmithyType

* Remove redundant thingy

* Add pointer to the output type if needed

* Update shape for recursive shape

* In native break all shapes to a function

* Fix map and list input type

* Fix union pointer and structure assertion

* Remove redundancy

* remove the package name

* Function all shapes in to native

* fix boolean for shape conv in func:

* Update for resource shape

* Update smithy name resolver

* remove redundant "}"

* fixes to reference of service type

* Output type for reference

* Add return

* Add type for service

* Revert change to service

* Handle service type output

* long and double to support pointer and non pointer type

* Fix Go Pointable

* Put all shapes to func

* remove redundant code

* Format

* Remove go mod

* Merge fix

* Fix returns

* Bring back dots

* Add go mod

* Update make file

* Fix wrappedIndex

* Add Go mod

* New codegen uses sdk id and service name

* New codegen uses sdk id

* Remove go mod

* add go mod

* add go mod

* update get smithy type in AWS

* Add generated shim because dafny generated name is camel case but not smithy generated

* Shim is generated in service shape namespace

* revert later

* Revert "revert later"

This reverts commit 7ae73f0.

* fixes

* Revert aggregate

* fixes

* Update recursive shape

* Add go mod

* fixes:

* fixes

* fix import
@rishav-karanjit rishav-karanjit changed the title (feat): Add support for recursive shapes in Go (#607) (feat): Add support for recursive shapes in Go Sep 23, 2024
@rishav-karanjit rishav-karanjit marked this pull request as ready for review September 23, 2024 18:25
@rishav-karanjit rishav-karanjit requested a review from a team as a code owner September 23, 2024 18:25
Copy link
Contributor

@ShubhamChaturvedi7 ShubhamChaturvedi7 left a comment

Choose a reason for hiding this comment

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

Reviewed the files under TestModels. Few top level comments:

  1. Always provide a description unless a PR is like very small. Your current reviewer might have context, but down the line people might read this PR to figure out the intention.
  2. Break PRs down into logical units. Easier to thoroughly review 2 small PRs than 1 huge PR.
  3. If changing Dafny name which affects other languages - call this out in TODO (unless you are prototyping / unblokcing someone but then you don't need a PR)
  4. Keep optimization / linting / formatting tasks in a different PR or call them out in description.

TestModels/LocalService/src/WrappedIndex.dfy Outdated Show resolved Hide resolved
TestModels/RecursiveShape/Makefile Outdated Show resolved Hide resolved
value: StructureWithRecursion
}

structure StructureWithRecursion {
Copy link
Contributor

Choose a reason for hiding this comment

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

Good Model :)

TestModels/RecursiveShape/removeDotFromExtern.sh Outdated Show resolved Hide resolved
TestModels/RecursiveShape/src/Index.dfy Show resolved Hide resolved
TestModels/RecursiveShape/src/SimpleRecursiveShapeImpl.dfy Outdated Show resolved Hide resolved
TestModels/aws-sdks/ddb/Model/model.json Outdated Show resolved Hide resolved
Copy link
Contributor

@ShubhamChaturvedi7 ShubhamChaturvedi7 left a comment

Choose a reason for hiding this comment

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

Look around the corner and see if any of the comments are applicable to other places as well, not just where it has been provided.

Comment on lines +6 to +7
#TODO: Think about extern processing in new test models
ENABLE_EXTERN_PROCESSING=1
Copy link
Contributor

Choose a reason for hiding this comment

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

Drop this since it's a new model and we don't need to rely on the sed processing. We don't want to set a precedence.

Copy link
Author

Choose a reason for hiding this comment

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

We still need sed processing because make polymorph_dafny will generate module {:extern "simple.recursiveshape.internaldafny.types" } SimpleRecursiveShapeTypes. Thats why there is a TODO.

Comment on lines +25 to +37
# Constants for languages that drop extern names (Python, Go)
# TODO: Before merging decide if we need this variables
TYPES_FILE_PATH=Model/SimpleRecursiveShapeTypes.dfy
TYPES_FILE_WITH_EXTERN_STRING="module {:extern \"simple.recursiveshape.internaldafny.types\" } SimpleRecursiveShapeTypes"
TYPES_FILE_WITHOUT_EXTERN_STRING="module SimpleRecursiveShapeTypes"

INDEX_FILE_PATH=src/Index.dfy
INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"simple.recursiveshape.internaldafny\"} SimpleRecursiveShape refines AbstractSimpleRecursiveShapeService {"
INDEX_FILE_WITHOUT_EXTERN_STRING="module SimpleRecursiveShape refines AbstractSimpleRecursiveShapeService {"

WRAPPED_INDEX_FILE_PATH=src/WrappedSimpleRecursiveShapeImpl.dfy
WRAPPED_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"simple.recursiveshape.internaldafny.wrapped\"} WrappedSimpleRecursiveShapeService refines WrappedAbstractSimpleRecursiveShapeService {"
WRAPPED_INDEX_FILE_WITHOUT_EXTERN_STRING="module WrappedSimpleRecursiveShapeService refines WrappedAbstractSimpleRecursiveShapeService {"
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, we don't need these.

Copy link
Author

Choose a reason for hiding this comment

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

No. We need TYPES_FILE sed processing because make polymorph_dafny will generate module {:extern "simple.recursiveshape.internaldafny.types" } SimpleRecursiveShapeTypes. INDEX_FILE and WRAPPED_INDEX are also needed because when ENABLE_EXTERN_PROCESSING=1 we will need TYPES_FILE, INDEX_FILE and WRAPPED_INDEX. Things will change in main between now and when we start merging the Go. Thats why there is a TODO.

@@ -0,0 +1,12 @@
module github.com/smithy-lang/smithy-dafny/TestModels/SimpleTypes/SimpleEnumV2
Copy link
Contributor

Choose a reason for hiding this comment

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

Leave it in since you've already implemented it.

@@ -0,0 +1,12 @@
module github.com/smithy-lang/smithy-dafny/TestModels/LocalService
Copy link
Contributor

Choose a reason for hiding this comment

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

Is LocalService implemented in Go?

Copy link
Author

Choose a reason for hiding this comment

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

Yes it is

ensures client.ValidState()
{
var myDataMap: MapWithRecursion := map[];
myDataMap := myDataMap["key2" := StructureWithRecursion(content := Some(IntegerValue(42)))];
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Do we need self assignment? Can we not just assign to the key?

Copy link
Author

Choose a reason for hiding this comment

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

Done in here: 1987f7d

@@ -322,6 +328,7 @@ public void generateSerializers(GenerationContext context) {
if (serviceShape.hasTrait(LocalServiceTrait.class)) {
generateConfigSerializer(context);
}
generateSerializerFunctions(context, alreadyVisited);
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO

Copy link
Author

Choose a reason for hiding this comment

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

Done

namespace.concat(
context.symbolProvider().toSymbol(serviceShape).getName()
),
dataSource
);
}
return """
func () *%s {
return func () *%s {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we discussed that we don't need these inline function calls anywhere. Let's see if we can get it done cheaply. Otherwise add a TODO.

Copy link
Author

Choose a reason for hiding this comment

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

I think if I just remove the function signature and make shape visitor return return <Implementation> this would "just" work as right now. However, I also think there could be a hidden failure that I am not thinking about right now. So, the best thing to do rn is to add TODO. When we have CI working fully and MPL in a stable state, I think at we should make an attempt to remove this anonymous function and test it.

@@ -198,31 +201,43 @@ public String structureShape(final StructureShape shape) {
),
DafnyNameResolver.dafnyTypesNamespace(shape)
);

String maybeAddress = (this.isOptional) ? "&" : "";
Copy link
Contributor

Choose a reason for hiding this comment

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

referenceType ?

Copy link
Author

Choose a reason for hiding this comment

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

Renamed it to referenceType


public class ShapeVisitorHelper {

public static final Map<MemberShape, Boolean> toDafnyOptionalityMap =
Copy link
Contributor

Choose a reason for hiding this comment

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

SNAKE_CASE

@@ -32,6 +32,26 @@ public static String getType(Symbol symbol, ServiceTrait serviceTrait) {
throw new RuntimeException("Failed to determine shape type");
}

public static String getType(final Symbol symbol, final Shape shape) {
// symbol.getProperty(SymbolUtils.GO_ELEMENT_TYPE, Symbol.class).isEmpty()
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove commented out code.

Copy link
Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

@ShubhamChaturvedi7 ShubhamChaturvedi7 left a comment

Choose a reason for hiding this comment

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

Added few final thoughts. I'm approving this PR since it has been open for long and likely things have changed on the other branch. Go ahead merge this PR in the Golang/dev branch and open a new PR with changes to address some of the comments.

}
alreadyVisited.add(visitingMemberShape.toShapeId());
var outputType = SmithyNameResolver.getSmithyTypeAws(serviceTrait, context.symbolProvider().toSymbol(visitingShape), true);
switch (visitingShape.getType()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

GoCodegenUtils.getType should take care of this. Add a TODO and fix it in another PR.

visitingMemberShape,
"FromDafny"
),
"interface {}",
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a TODO because we should be able to use the native type instead of the interface.

final var memberName = context.symbolProvider().toMemberName(member);
// unwrap union type, assert it then convert it to its member type with Dtor_ (example: Dtor_BlobValue()). unionDataSource is not a wrapper object until now.
var unionDataSource = dataSource.concat(".Dtor_").concat(memberName.replace(shape.getId().getName().concat("Member"), "")).concat("()");
final var isMemberShapePointable = (awsSdkGoPointableIndex.isPointable(targetShape) && awsSdkGoPointableIndex.isDereferencable(targetShape)) && !targetShape.isStructureShape();
Copy link
Contributor

Choose a reason for hiding this comment

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

Next PR: Check if you can just use the awsSdkGoPointableIndex.isPointable(memberShape)

Comment on lines +61 to +66
return memberShape
.getId()
.toString()
.replaceAll("[.$#]", "_")
.concat("_")
.concat(suffix);
Copy link
Contributor

Choose a reason for hiding this comment

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

Use the namespace and name concat.

for (final MemberShape key : validationFuncMap.keySet()) {
String inputType = "";
if (validationFuncInputTypeMap.containsKey(key)) {
inputType = "Value ".concat(validationFuncInputTypeMap.get(key));
Copy link
Contributor

Choose a reason for hiding this comment

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

Use Value %s.format()` otherwise it's hard to read the whitespace.

return nil
if (isOptional) {
return """
return func () *float64 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use the if check with %s to figure out if it's a pointer or not.

Copy link
Author

Choose a reason for hiding this comment

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

Let's do this as a clean up task at the end. Every non container shape is written in this way. I will add a TODO.

@rishav-karanjit rishav-karanjit merged commit f04495a into Golang/dev Oct 16, 2024
14 of 108 checks passed
@rishav-karanjit rishav-karanjit deleted the add-recursive-Go branch October 17, 2024 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants