An object literal field the receiver's type cannot hold is an error - #517
Merged
Merged
Conversation
`let s: Sq = ...; s = { kind: "ci", r: 1 }` (Sq = { kind: "sq"; side:
number }) compiled with no error and left `s` unchanged (#513). The same
literal in a declaration, `let t: Sq = { kind: "ci", r: 1 }`, compiled
and held garbage.
addObjectFieldInfo cast each field to the receiver's field type and
took the result as a value. The cast of "ci" to the literal type "sq"
failed and reported it, but a failed cast is a null value: the field
was queued with no value, the literal came out with no value at all,
and an assignment of no value stores nothing and still succeeds.
MLIRGen postpones its messages and shows them only if the module fails
to compile. Nothing failed, so the cast's error was never shown.
A field whose cast fails now fails the literal, so its error is shown.
As an argument the literal was already an error, with a misleading
"Expected 1 arguments, but got 0" next to the real one; that message
is gone.
literal-field-mismatch/: an assignment, a declaration, an argument and
a return of `{ kind: "ci", r: 1 }` where an Sq is expected. Each must
report the cast error, and no arity error. On main the assignment and
the declaration compile with no error. positive.ts assigns, declares,
passes and returns matching literals, and a union receiver still picks
its member.
Closes #513
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hecks
`{ left: null }` for a `left: Point` is an error under strict null
checks, which are on by default: null is not a Point, as in
`let p: Point = null`. The test compiled only because the field's
failed cast was dropped (#513), and the field read null by default.
With that cast now an error, the file says what it relies on. The test
is about a cross-module object literal with class-typed fields, not
null checking.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #513.
let s: Sq = { kind: "sq", side: 4 }; s = { kind: "ci", r: 1 }(withSq = { kind: "sq"; side: number }) compiled with no error and leftsunchanged. The same literal used elsewhere was also wrong:let t: Sq = { kind: "ci", r: 1 }) it compiled and held garbage;Cause
addObjectFieldInfocasts each field of an object literal to the receiver's field type and took the result as a value. The cast of"ci"to the literal type"sq"failed and reported it. But a failed cast is a null value:MLIRGen postpones its messages and shows them only if the module fails to compile. Nothing failed, so the cast's error was never shown.
Change
A field whose cast fails now fails the literal, so the existing error is shown:
One existing test relied on the dropped cast
export_object_literal_with_class_types.tsinitializesleft: Pointwithnull. Strict null checks are on by default, and under them that is an error, in TypeScript and in tslang (let p: Point = nullis rejected the same way). It compiled only because the field's cast was dropped and the field read null by default.The test is about a cross-module object literal with class-typed fields, not null checking. So it now starts with
// @strict-null false(as28boolcasts.tsdoes), in a commit of its own.Tests
literal-field-mismatch/has four files:assign.ts,declare.ts,argument.ts,return.ts:{ kind: "ci", r: 1 }where anSqis expected. Each must report the cast error, and no arity error. On main, the assignment and the declaration compile with no error.positive.ts: matching literals assign, declare, pass and return, and a union receiver still picks its member.Verification
ctest -C Release, full run: 7 failures, all the test above (its 6 registrations plus its ownership-verifier shard). With the pragma, all 7 pass. The other 3875 passed in the full run. gtest unittests are not built in this tree.origin/main) built with this compiler, since the change turns silent failures into errors: gc and rc build with no errors. Release tests: gc 160/160, rc 159/160 (1 gc-only skip).src/lib.tsalso compiles directly under both models.Not changed
Two other mismatches still compile, and neither drops a store:
side: "x"where a number is expected is converted (it reads 0). That is tslang's conversion rule.{ kind: "sq", side: 5, extra: 1 }) is accepted and stored. TypeScript reports excess properties in a literal assigned to a declared type.🤖 Generated with Claude Code