Skip to content

Fix l1-config-types-object language test#2190

Open
iwahbe wants to merge 9 commits into
mainfrom
iwahbe/fix-l1-config-types-object-v2
Open

Fix l1-config-types-object language test#2190
iwahbe wants to merge 9 commits into
mainfrom
iwahbe/fix-l1-config-types-object-v2

Conversation

@iwahbe
Copy link
Copy Markdown
Member

@iwahbe iwahbe commented May 18, 2026

Summary

Implements l1-config-types-object by teaching the Java program codegen to handle map, object, and dynamic configuration types.

  • object(...) configs: synthesize a nested static class <Name>Config inside App with a private field and method accessor per property. The retrieval call becomes config.requireObject(\"<key>\", <Name>Config.class), which Gson deserializes via reflection.
  • map(...) configs: lower to config.requireObject(key, TypeShape.map(String.class, <Element>.class)), with attribute and index access generating .get(key) for the resulting java.util.Map.
  • Dynamic / untyped configs (config \"x\" {}): retrieved as Map<String, Object> via the dynamic TypeShape. The intrinsic-convert lowering emits a ((Number) ...).doubleValue() / ((Boolean) ...) / ((String) ...) cast so arithmetic and equality on dynamic values compiles. The traversal tracks when it has crossed a dynamic boundary and inserts a (java.util.List) cast before any subsequent list indexing.
  • SDK: adds Config.requireObject(key, TypeShape) and Config.requireSecretObject(key, TypeShape), mirroring the existing Class<T> overloads.

Fixes #2005.

Test plan

  • `go test -run 'TestLanguage/l1-config-types-object$' ./pkg/cmd/pulumi-language-java/`
  • `go test -run TestGenerateJavaProgram ./pkg/codegen/...`
  • `make lint`
  • `cd sdk/java && ./gradlew build`

iwahbe added 6 commits May 18, 2026 16:29
Resolve the `l1-config-types-object` conformance failure by lowering
inline `object(...)`, `map(...)`, and dynamic configuration types to
`Map<String, Object>` (or `Map<String, ELEMENT>` for typed maps) via
the new `requireObject(key, TypeShape)` SDK overloads, and by rewiring
the traversal/expression pipeline so that attribute and index access
on those values uses Java collection semantics.

- `genConfigVariable` chooses `requireObject`/`getObject` with a
  generated `TypeShape` for map, object, and dynamic config kinds.
- Add `requireObject(key, TypeShape)` and
  `requireSecretObject(key, TypeShape)` to `com.pulumi.Config`.
- `genRelativeTraversal` now buffers the chain and switches attribute
  steps to `.get("key")` when the root is a `*pcl.ConfigVariable` of
  map/object/dynamic kind; list indexing on a value whose Java static
  type has been erased to `Object` is wrapped in a `(java.util.List)`
  cast.
- `GenIndexExpression` lowers `aMap[k]` to `aMap.get(k)` for
  `*model.MapType`/dynamic collections.
- `genIntrinsic` emits explicit numeric/boolean/string casts when
  converting from a dynamically-typed value to a concrete type, so
  arithmetic like `anyObject.a + anyObject.b` compiles.
- Regenerate two program-codegen golden files that relied on
  `[idx]` indexing of Java `List` values, which never actually
  compiled in Java.

Fixes #2005
For each `config "<name>" "object({...})" {}` declaration the Java
codegen now emits a nested static class `<Name>Config` containing a
Gson-deserializable public field and a method accessor per property.
The config retrieval call uses `requireObject(key, <Name>Config.class)`
and traversals use the existing `.attr()` getter style — no
`Map<String, Object>` lowering, no runtime casts.

Drop the `objectAsMap` flag and the `(java.util.List)` cast injection
that worked around the previous Map-based lowering; `*model.ObjectType`
now uniformly uses method accessors, matching how the synthetic `range`
iteration variable and schema-typed resource outputs already worked.

Dynamic / untyped (`config "x" {}`) values still come back as
`Map<String, Object>` since their shape isn't known at codegen time.
@iwahbe iwahbe force-pushed the iwahbe/fix-l1-config-types-object-v2 branch from 0f8d7dd to e59bd2c Compare May 19, 2026 08:40
iwahbe added 3 commits May 19, 2026 10:46
- Drop `staticTypeErased` bookkeeping and `mapValueErasesToObject`.
  These guarded a `(java.util.List)` cast injection for traversals that
  crossed a `Map<String, Object>` boundary. With typed POJOs for
  `object(...)` configs the only remaining `Map<String, Object>` source
  is a `dynamic` config, and PCL traversal on dynamic stays dynamic
  rather than becoming a list — so the cast branch was unreachable.
- `genRelativeTraversal` now writes directly to the output writer
  instead of buffering a `chain` string.
- `genConfigVariable` defaults `typeSuffix` to `"Object"` and overrides
  it only for the primitive cases, removing duplicate assignments.
- `isMapLikeType`/`isListLikeType` no longer unwrap optionals; callers
  do it once at the top, so we don't traverse the union twice.
@iwahbe iwahbe marked this pull request as ready for review May 19, 2026 09:00
@iwahbe iwahbe requested a review from a team as a code owner May 19, 2026 09:00
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.

Implement l1-config-types-object

1 participant