Skip to content

fix: resolve field/2 ambiguous import in inline embeds#2

Merged
fahchen merged 3 commits intomainfrom
fix/inline-embeds-ambiguous-import
Apr 17, 2026
Merged

fix: resolve field/2 ambiguous import in inline embeds#2
fahchen merged 3 commits intomainfrom
fix/inline-embeds-ambiguous-import

Conversation

@fahchen
Copy link
Copy Markdown
Member

@fahchen fahchen commented Apr 17, 2026

Summary

  • Fix field/2 imported from both Ecto.Schema and EctoTypedSchema, call is ambiguous error when using field inside inline embeds_one/embeds_many do-blocks
  • Inline child modules now get proper @type t() generation via EctoTypedSchema (previously only got bare Ecto.Schema with no typespec)

Root Cause

Ecto.Schema.embeds_one/4 calls __embeds_module__(__ENV__, ...) which creates the child module via Module.create/3 carrying the caller's __ENV__ — including EctoTypedSchema's field/2 import. When the child module then use Ecto.Schema, both field/2 imports collide.

Fix

Instead of delegating to Ecto.Schema.embeds_one/4, create inline child modules with use EctoTypedSchema + typed_embedded_schema, then call Ecto.Schema.__embeds_one__/4 directly. Added expand_nested_module_alias/2 to resolve child module names relative to the parent, matching Ecto's own behavior.

Test plan

  • Inline embeds_one compiles with plain field in do-block (was ambiguous import error)
  • Inline embeds_many compiles with plain field in do-block
  • Child modules get @type t() with correct fields
  • typed: [null: false] on inline embeds works
  • primary_key: false forwarded to child module
  • on_replace: :delete Ecto opt forwarded correctly
  • 149 tests pass, dialyzer clean, no warnings

🤖 Generated with Claude Code

fahchen and others added 3 commits April 17, 2026 18:24
Inline `embeds_one/embeds_many` with do-blocks previously delegated to
`Ecto.Schema.embeds_one/4`, which creates child modules via
`Module.create/3` carrying the caller's `__ENV__` — including
EctoTypedSchema's `field/2` import. When the child module then
`use Ecto.Schema`, both `field/2` imports collide.

Fix: create inline child modules ourselves with `use EctoTypedSchema` +
`typed_embedded_schema`, then call `Ecto.Schema.__embeds_one__/4`
directly. This also gives inline embed modules proper `@type t()`
generation, which they previously lacked.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove Ecto.Schema.field() workaround from expected blocks — plain
`field` works inside Ecto.Schema inline embed do-blocks too. Add test
for multi-level nested inline embeds (parent → Shipping → Address)
to verify the fix works recursively.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace regex `=~` assertions with normalized exact `==` matching.
normalize_type/1 strips the module prefix and collapses whitespace
so assertions are deterministic regardless of module path length.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fahchen fahchen merged commit 9e639b4 into main Apr 17, 2026
4 checks passed
@fahchen fahchen deleted the fix/inline-embeds-ambiguous-import branch April 17, 2026 09:42
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.

1 participant