Skip to content

Commit

Permalink
[program-gen] Fix generation of untyped maps and array literals (#1581)
Browse files Browse the repository at this point in the history
### Description

Fixes how we are generating map and array literals when they are
_untyped_. The problem was that we generated just the elements i.e. `[1,
2, 3]` in PCL would generate `1, 2, 3` in java because Array-typed
resource inputs accepts the elements being spread like that i.e.
`resourceInputs = [1,2,3]` (PCL) generated `resourceInputs(1, 2, 3)`
(Java). However this doesn't work when we are initializing lists and
maps outside of resource inputs: local variables and output variables.

This PR addresses the problem by using `Map.ofEntries(...)` and
`List.of(...)` when applicable.

Branch is written on top of #1580

- Fixes #1561 
- Fixes #1560 
- Unskips `l1-output-map`
- Unskips `l1-output-array`
  • Loading branch information
Zaid-Ajaj authored Jan 9, 2025
1 parent 70c572a commit 84e513c
Show file tree
Hide file tree
Showing 12 changed files with 475 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
- Fix emitted functions for `assetArchive` and `remoteAsset` in generated programs
- Fix generation of `double` literals in generated programs
- Avoid calling invokes with dependencies on unknown resources
- Fix generation of untyped maps and array literals

### Bug Fixes
2 changes: 0 additions & 2 deletions pkg/cmd/pulumi-language-java/language_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ func TestLanguage(t *testing.T) {
// expectedFailures maps the set of conformance tests we expect to fail to reasons they currently do so, so that we may
// skip them with an informative message until they are fixed.
var expectedFailures = map[string]string{
"l1-output-array": "#1560 Empty array literals are not generated correctly",
"l1-output-map": "#1561 Map literals are not generated correctly",
"l1-output-string": "#1562 Large string literals are not generated correctly",
"l2-invoke-options": "#1563 Invoke argument and result handling",
"l2-invoke-options-depends-on": "#1563 Invoke argument and result handling",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name: l1-output-array
runtime: java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.pulumi</groupId>
<artifactId>l1-output-array</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<encoding>UTF-8</encoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.release>11</maven.compiler.release>
<mainClass>generated_program.App</mainClass>
<mainArgs/>
</properties>

<repositories>
<repository>
<id>repository-0</id>
<url>REPOSITORY</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>com.pulumi</groupId>
<artifactId>pulumi</artifactId>
<version>CORE.VERSION</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>${mainClass}</mainClass>
<commandlineArgs>${mainArgs}</commandlineArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-wrapper-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<mavenVersion>3.8.5</mavenVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name: l1-output-map
runtime: java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.pulumi</groupId>
<artifactId>l1-output-map</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<encoding>UTF-8</encoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.release>11</maven.compiler.release>
<mainClass>generated_program.App</mainClass>
<mainArgs/>
</properties>

<repositories>
<repository>
<id>repository-0</id>
<url>REPOSITORY</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>com.pulumi</groupId>
<artifactId>pulumi</artifactId>
<version>CORE.VERSION</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>${mainClass}</mainClass>
<commandlineArgs>${mainArgs}</commandlineArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-wrapper-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<mavenVersion>3.8.5</mavenVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}

public static void stack(Context ctx) {
ctx.export("empty", Map.ofEntries(
));
ctx.export("strings", Map.ofEntries(
Map.entry("greeting", "Hello, world!"),
Map.entry("farewell", "Goodbye, world!")
));
ctx.export("numbers", Map.ofEntries(
Map.entry("1", 1),
Map.entry("2", 2)
));
ctx.export("keys", Map.ofEntries(
Map.entry("my.key", 1),
Map.entry("my-key", 2),
Map.entry("my_key", 3),
Map.entry("MY_KEY", 4),
Map.entry("mykey", 5),
Map.entry("MYKEY", 6)
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static void stack(Context ctx) {
ctx.export("outputInput", SimpleinvokeFunctions.myInvoke(MyInvokeArgs.builder()
.value(res.text())
.build()).applyValue(invoke -> invoke.result()));
ctx.export("unit", SimpleinvokeFunctions.unit().applyValue(invoke -> invoke.result()));
ctx.export("unit", SimpleinvokeFunctions.unit(UnitArgs.builder()
.build()).applyValue(invoke -> invoke.result()));
}
}
71 changes: 41 additions & 30 deletions pkg/codegen/java/gen_program_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,6 @@ func (g *generator) GenObjectConsExpression(w io.Writer, expr *model.ObjectConsE
}

func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression, destType schema.Type) {
if len(expr.Items) == 0 {
return
}

g.genObjectConsExpressionWithTypeName(w, expr, destType)
}

Expand Down Expand Up @@ -595,13 +591,9 @@ func pickTypeFromUnion(union *schema.UnionType, expr *model.ObjectConsExpression
func (g *generator) genObjectConsExpressionWithTypeName(
w io.Writer, expr *model.ObjectConsExpression, destType schema.Type,
) {
if len(expr.Items) == 0 {
return
}

destTypeName := typeName(destType)
switch destType := destType.(type) {
case *schema.ObjectType:
destTypeName := typeName(destType)
objectProperties := make(map[string]schema.Type)
for _, property := range destType.Properties {
objectProperties[property.Name] = codegen.UnwrapType(property.Type)
Expand Down Expand Up @@ -803,30 +795,49 @@ func (g *generator) GenTupleConsExpression(w io.Writer, expr *model.TupleConsExp
}
}

if len(expr.Expressions) > 0 {
if len(expr.Expressions) == 1 {
// simple case, just write the first element
g.Fgenf(w, "%.v", expr.Expressions[0])
return
closeList := func() {
if g.currentResourcePropertyType == nil {
g.Fgen(w, ")")
}
}

// Write multiple list elements
g.Fgenf(w, "%s\n", g.Indent)
g.Indented(func() {
for index, value := range expr.Expressions {
if index == 0 {
// first expression, no need for a new line
g.Fgenf(w, "%s%.v,", g.Indent, value)
} else if index == len(expr.Expressions)-1 {
// last element, no trailing comma
g.Fgenf(w, "\n%s%.v", g.Indent, value)
} else {
// elements in between: new line and trailing comma
g.Fgenf(w, "\n%s%.v,", g.Indent, value)
}
}
})
if g.currentResourcePropertyType == nil {
// we are dealing with an untyped array
// generate `List.of(...)`
g.Fgen(w, "List.of(")
}

if len(expr.Expressions) == 0 {
// empty list
closeList()
return
}

if len(expr.Expressions) == 1 {
// simple case, just write the first element
g.Fgenf(w, "%.v", expr.Expressions[0])
closeList()
return
}

// Write multiple list elements
g.Fgenf(w, "%s\n", g.Indent)
g.Indented(func() {
for index, value := range expr.Expressions {
if index == 0 {
// first expression, no need for a new line
g.Fgenf(w, "%s%.v,", g.Indent, value)
} else if index == len(expr.Expressions)-1 {
// last element, no trailing comma
g.Fgenf(w, "\n%s%.v", g.Indent, value)
} else {
// elements in between: new line and trailing comma
g.Fgenf(w, "\n%s%.v,", g.Indent, value)
}
}
})

closeList()
}

func (g *generator) GenUnaryOpExpression(w io.Writer, _ *model.UnaryOpExpression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public static void stack(Context ctx) {
.build());

// Subnets, one for each AZ in a region
final var zones = AwsFunctions.getAvailabilityZones();
final var zones = AwsFunctions.getAvailabilityZones(GetAvailabilityZonesArgs.builder()
.build());

final var vpcSubnet = zones.applyValue(getAvailabilityZonesResult -> {
final var resources = new ArrayList<Subnet>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public static void main(String[] args) {
}

public static void stack(Context ctx) {
final var zones = AwsFunctions.getAvailabilityZones();
final var zones = AwsFunctions.getAvailabilityZones(GetAvailabilityZonesArgs.builder()
.build());

final var vpcSubnet = zones.applyValue(getAvailabilityZonesResult -> {
final var resources = new ArrayList<Subnet>();
Expand Down

0 comments on commit 84e513c

Please sign in to comment.