Skip to content

new of a generic class takes its type arguments from the receiver - #382

Merged
ASDAlexander77 merged 1 commit into
mainfrom
new-generic-type-args-from-receiver
Sep 28, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
new-generic-type-args-from-receiver

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Found in EventTarget.ts of the BrowserLib sources attached to #231. That is the can't find type by name: EventListenerCallback item listed there: the error was a symptom of this bug.

const m: Map<string, number[]> = new Map();   // crashed at run time (0xC0000005)
m.set("a", [5]);

class Box<T> { … }
const b: Box<number> = new Box();              // error: Generic class 'Box' is missing type arguments

TypeScript takes the type arguments of new C() from the type the value is given to. tslang did not:

  • A generic with type-parameter defaults: Map is class Map<K = any, V = any>, so new Map() became Map<any, any>. The initializer then cast it to Map<string, number[]>, a different specialization with a different layout. The first set crashed at run time. This happens on older builds too.
  • A generic without defaults: a compile error.

Fix

In mlirGen(NewExpression), a new written without type arguments uses the receiver's type when that type is a specialization of the same generic class. The comparison uses ClassInfo::originClassType. It applies when the class named is either the generic itself or its specialization by the defaults.

The receiver is the receiverType that is already passed down for:

  • a declared variable;
  • a field initializer;
  • the right side of an assignment.

Explicit type arguments are unchanged, and so is a receiver of any other type.

Tests

  • New 00new_generic_from_receiver.ts (compile, jit, and the rc/none corpus). It covers:

    • a plain generic;
    • a generic with defaults;
    • a declared variable, an assignment, a field initializer and a constructor assignment;
    • explicit type arguments.

    The old build fails it with "missing type arguments".

  • Full release suite: 2993/2993 passed.

  • TypeScriptCompilerDefaultLib tests, release jit and compile: 156/156 each.

  • BrowserLib EventTarget.ts no longer reports EventListenerCallback. What is left there is the existing rule that push on a const local array is an error, plus the missing splice.

Not in this PR

A cast between two different specializations of one generic class, such as Map<any, any> to Map<string, number[]>, is still accepted silently. That is what turned this into a run-time crash. It should be a compile error.

🤖 Generated with Claude Code

`const m: Map<string, number[]> = new Map()` crashed at run time: Map is
declared `Map<K = any, V = any>`, so `new Map()` built Map<any, any>, and the
cast to the declared type reinterpreted it as a different layout. A generic
without defaults was a compile error instead ("Generic class 'Box' is missing
type arguments"). Found in the BrowserLib sources attached to #231
(EventTarget.ts, `listeners: Map<string, EventListenerCallback[]> = new Map()`).

A `new` without type arguments now takes the receiver's specialization (the
declared variable, field or assignment target) when that is a specialization
of the same generic class. Explicit type arguments are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 5017269 into main Sep 28, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the new-generic-type-args-from-receiver branch September 28, 2026 08:26
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