Repository: microsoft/TypeScript
File: src/compiler/expressionToTypeNode.ts (TypeScript)

Code before:
        if (!(context.flags & NodeBuilderFlags.MultilineObjectLiterals)) {
            setEmitFlags(typeNode, EmitFlags.SingleLine);
        }
        context.noInferenceFallback = oldNoInferenceFallback;
        return notImplemented;
    }

    function typeFromObjectLiteralPropertyAssignment(prop: PropertyAssignment, name: PropertyName, context: SyntacticTypeNodeBuilderContext, isConstContext: boolean) {
        const modifiers = isConstContext ?
            [factory.createModifier(SyntaxKind.ReadonlyKeyword)] :
            [];
        const expressionResult = typeFromExpression(prop.initializer, context, isConstContext);
        const typeNode = expressionResult.type !== undefined ? expressionResult.type : inferTypeOfDeclaration(prop, /*symbol*/ undefined, context, expressionResult.reportFallback);

        return factory.createPropertySignature(
            modifiers,
            reuseNode(context, name),
            /*questionToken*/ undefined,
            typeNode,
        );
    }

    function ensureParameter(p: ParameterDeclaration, context: SyntacticTypeNodeBuilderContext) {
        return factory.updateParameterDeclaration(
            p,
            p.modifiers,
            reuseNode(context, p.dotDotDotToken),
            resolver.serializeNameOfParameter(context, p),
            resolver.isOptionalParameter(p) ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
            typeFromParameter(p, /*symbol*/ undefined, context), // Ignore private param props, since this type is going straight back into a param
            /*initializer*/ undefined,
        );
    }
    function reuseTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration> | undefined, context: SyntacticTypeNodeBuilderContext) {
        return typeParameters?.map(tp =>
            factory.updateTypeParameterDeclaration(
                tp,
                tp.modifiers?.map(m => reuseNode(context, m)),
                reuseNode(context, tp.name),
                serializeExistingTypeNodeWithFallback(tp.constraint, context),
                serializeExistingTypeNodeWithFallback(tp.default, context),
            )
        );
    }

    function typeFromObjectLiteralMethod(method: MethodDeclaration, name: PropertyName, context: SyntacticTypeNodeBuilderContext, isConstContext: boolean) {
        const returnType = createReturnFromSignature(method, /*symbol*/ undefined, context);
        const typeParameters = reuseTypeParameters(method.typeParameters, context);
        const parameters = method.parameters.map(p => ensureParameter(p, context));
        if (isConstContext) {
            return factory.createPropertySignature(

Review comment (bug):
The crash was caused by `getPos` rying to read `.__pos` that is meant to be added by `onBeforeEmitNodeArray` (called by `emitDecoratorsAndModifiers`, called by `emitParameter`). But since this list was empty it just bailed on it:
https://github.com/microsoft/TypeScript/blob/b3c67d32020a3015fe068fbcb1dcfb18aedcaad3/src/compiler/emitter.ts#L4435-L4436

This fix tries to reuse existing `p.modifiers` (it feels like `ensureParameter` shouldn't try to *los* information). Since the parameters in question don't have any modifiers an `undefined` gets "reused". So then the printer doesn't crash on lacking `.__pos` because it doesn't even have see the related node array as it wasn't created in the first place.

This, of course, means that this can still crash, in a similar way, on empty modifiers if they are ever returned. 

I think it would be best to keep the current fix (it avoids allocating a redundant empty array) but also call `onBeforeEmitNodeArray` on empty `modifiers` in `emitDecoratorsAndModifiers`. I glanced through the whole `emitter.ts` and it seems like it's the only function that avoids it. Do you think there is some extra test case to be written that would prove it **needs** to be done there?



This, of course, means that any similar 

Code after:
        if (!(context.flags & NodeBuilderFlags.MultilineObjectLiterals)) {
            setEmitFlags(typeNode, EmitFlags.SingleLine);
        }
        context.noInferenceFallback = oldNoInferenceFallback;
        return notImplemented;
    }

    function typeFromObjectLiteralPropertyAssignment(prop: PropertyAssignment, name: PropertyName, context: SyntacticTypeNodeBuilderContext, isConstContext: boolean) {
        const modifiers = isConstContext ?
            [factory.createModifier(SyntaxKind.ReadonlyKeyword)] :
            [];
        const expressionResult = typeFromExpression(prop.initializer, context, isConstContext);
        const typeNode = expressionResult.type !== undefined ? expressionResult.type : inferTypeOfDeclaration(prop, /*symbol*/ undefined, context, expressionResult.reportFallback);

        return factory.createPropertySignature(
            modifiers,
            reuseNode(context, name),
            /*questionToken*/ undefined,
            typeNode,
        );
    }

    function ensureParameter(p: ParameterDeclaration, context: SyntacticTypeNodeBuilderContext) {
        return factory.updateParameterDeclaration(
            p,
            /*modifiers*/ undefined,
            reuseNode(context, p.dotDotDotToken),
            resolver.serializeNameOfParameter(context, p),
            resolver.isOptionalParameter(p) ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
            typeFromParameter(p, /*symbol*/ undefined, context), // Ignore private param props, since this type is going straight back into a param
            /*initializer*/ undefined,
        );
    }
    function reuseTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration> | undefined, context: SyntacticTypeNodeBuilderContext) {
        return typeParameters?.map(tp =>
            factory.updateTypeParameterDeclaration(
                tp,
                tp.modifiers?.map(m => reuseNode(context, m)),
                reuseNode(context, tp.name),
                serializeExistingTypeNodeWithFallback(tp.constraint, context),
                serializeExistingTypeNodeWithFallback(tp.default, context),
            )
        );
    }

    function typeFromObjectLiteralMethod(method: MethodDeclaration, name: PropertyName, context: SyntacticTypeNodeBuilderContext, isConstContext: boolean) {
        const returnType = createReturnFromSignature(method, /*symbol*/ undefined, context);
        const typeParameters = reuseTypeParameters(method.typeParameters, context);
        const parameters = method.parameters.map(p => ensureParameter(p, context));
        if (isConstContext) {
            return factory.createPropertySignature(