Repository: rollup/rollup
File: src/ast/nodes/shared/FunctionNode.ts (TypeScript)

Code before:
import { type HasEffectsContext, type InclusionContext } from '../../ExecutionContext';
import type { NodeInteraction } from '../../NodeInteractions';
import { INTERACTION_CALLED } from '../../NodeInteractions';
import type ChildScope from '../../scopes/ChildScope';
import FunctionScope from '../../scopes/FunctionScope';
import {
	EMPTY_PATH,
	type EntityPathTracker,
	type ObjectPath,
	UNKNOWN_PATH
} from '../../utils/PathTracker';
import type BlockStatement from '../BlockStatement';
import Identifier, { type IdentifierWithVariable } from '../Identifier';
import { UNKNOWN_EXPRESSION } from './Expression';
import FunctionBase from './FunctionBase';
import { type IncludeChildren } from './Node';
import { ObjectEntity } from './ObjectEntity';
import { OBJECT_PROTOTYPE } from './ObjectPrototype';
import type { DeclarationPatternNode } from './Pattern';

export default class FunctionNode extends FunctionBase {
	body!: BlockStatement;
	id!: IdentifierWithVariable | null;
	params!: DeclarationPatternNode[];
	preventChildBlockScope!: true;
	scope!: FunctionScope;
	protected objectEntity: ObjectEntity | null = null;
	private constructedEntity!: ObjectEntity;

	createScope(parentScope: ChildScope): void {
		this.scope = new FunctionScope(parentScope, this);
		this.constructedEntity = new ObjectEntity(new Map(), OBJECT_PROTOTYPE);
		// This makes sure that all deoptimizations of "this" are applied to the
		// constructed entity.
		this.scope.thisVariable.addArgumentForDeoptimization(this.constructedEntity);
	}

	deoptimizeArgumentsOnInteractionAtPath(
		interaction: NodeInteraction,
		path: ObjectPath,
		recursionTracker: EntityPathTracker
	): void {
		super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
		if (interaction.type === INTERACTION_CALLED && path.length === 0 && interaction.args[0]) {
			// args[0] is the "this" argument
			this.scope.thisVariable.addArgumentForDeoptimization(interaction.args[0]);
		}
	}

	hasEffects(context: HasEffectsContext): boolean {
		if (this.annotationNoSideEffects) {

Review comment (suggestion):
`preventChildBlockScope` is meant to be provided via `FunctionBase.prototype.preventChildBlockScope = true`. Declaring `preventChildBlockScope!: true` here emits an instance field initialized to `undefined`, which shadows the prototype flag and makes it falsy at runtime. This should be `declare preventChildBlockScope: true` (type-only) or initialized to `true`.

Code after:
import { type HasEffectsContext, type InclusionContext } from '../../ExecutionContext';
import type { NodeInteraction } from '../../NodeInteractions';
import { INTERACTION_CALLED } from '../../NodeInteractions';
import type ChildScope from '../../scopes/ChildScope';
import FunctionScope from '../../scopes/FunctionScope';
import {
	EMPTY_PATH,
	type EntityPathTracker,
	type ObjectPath,
	UNKNOWN_PATH
} from '../../utils/PathTracker';
import type BlockStatement from '../BlockStatement';
import Identifier, { type IdentifierWithVariable } from '../Identifier';
import { UNKNOWN_EXPRESSION } from './Expression';
import FunctionBase from './FunctionBase';
import { type IncludeChildren } from './Node';
import { ObjectEntity } from './ObjectEntity';
import { OBJECT_PROTOTYPE } from './ObjectPrototype';
import type { DeclarationPatternNode } from './Pattern';

export default class FunctionNode extends FunctionBase {
	declare body: BlockStatement;
	declare id: IdentifierWithVariable | null;
	declare params: DeclarationPatternNode[];
	declare preventChildBlockScope: true;
	declare scope: FunctionScope;
	protected objectEntity: ObjectEntity | null = null;
	declare private constructedEntity: ObjectEntity;

	createScope(parentScope: ChildScope): void {
		this.scope = new FunctionScope(parentScope, this);
		this.constructedEntity = new ObjectEntity(new Map(), OBJECT_PROTOTYPE);
		// This makes sure that all deoptimizations of "this" are applied to the
		// constructed entity.
		this.scope.thisVariable.addArgumentForDeoptimization(this.constructedEntity);
	}

	deoptimizeArgumentsOnInteractionAtPath(
		interaction: NodeInteraction,
		path: ObjectPath,
		recursionTracker: EntityPathTracker
	): void {
		super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
		if (interaction.type === INTERACTION_CALLED && path.length === 0 && interaction.args[0]) {
			// args[0] is the "this" argument
			this.scope.thisVariable.addArgumentForDeoptimization(interaction.args[0]);
		}
	}

	hasEffects(context: HasEffectsContext): boolean {
		if (this.annotationNoSideEffects) {