Repository: rollup/rollup
File: src/ast/scopes/ModuleScope.ts (TypeScript)

Code before:
import type { AstContext, ImportDescription } from '../../Module';
import type { InternalModuleFormat } from '../../rollup/types';
import { logRedeclarationError } from '../../utils/logs';
import type ExportDefaultDeclaration from '../nodes/ExportDefaultDeclaration';
import type Identifier from '../nodes/Identifier';
import type { ExpressionEntity } from '../nodes/shared/Expression';
import type { VariableKind } from '../nodes/shared/VariableKinds';
import type { ObjectPath } from '../utils/PathTracker';
import { EMPTY_PATH } from '../utils/PathTracker';
import { UNDEFINED_EXPRESSION } from '../values';
import ExportDefaultVariable from '../variables/ExportDefaultVariable';
import GlobalVariable from '../variables/GlobalVariable';
import LocalVariable from '../variables/LocalVariable';
import type Variable from '../variables/Variable';
import ChildScope from './ChildScope';
import type GlobalScope from './GlobalScope';

export default class ModuleScope extends ChildScope {
	parent!: GlobalScope;

	constructor(
		parent: GlobalScope,
		context: AstContext,
		private readonly importDescriptions: Map<string, ImportDescription>
	) {
		super(parent, context);
		this.variables.set(
			'this',
			new LocalVariable('this', null, UNDEFINED_EXPRESSION, EMPTY_PATH, context, 'other')
		);
	}

	addDeclaration(
		identifier: Identifier,
		context: AstContext,
		init: ExpressionEntity,
		destructuredInitPath: ObjectPath,
		kind: VariableKind
	): LocalVariable {
		if (this.importDescriptions.has(identifier.name)) {
			context.error(logRedeclarationError(identifier.name), identifier.start);
		}
		return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
	}

Review comment (suggestion):
`ChildScope` already defines `readonly parent` via a parameter property and initializes it in the base constructor. Declaring `parent!: GlobalScope` here will emit a class-field initializer that runs after `super(...)` and overwrites `this.parent` back to `undefined`, breaking lookups like `this.parent.findVariable(...)`. Use a type-only override instead (e.g. `declare override readonly parent: GlobalScope`) rather than a runtime field.

Code after:
import type { AstContext, ImportDescription } from '../../Module';
import type { InternalModuleFormat } from '../../rollup/types';
import { logRedeclarationError } from '../../utils/logs';
import type ExportDefaultDeclaration from '../nodes/ExportDefaultDeclaration';
import type Identifier from '../nodes/Identifier';
import type { ExpressionEntity } from '../nodes/shared/Expression';
import type { VariableKind } from '../nodes/shared/VariableKinds';
import type { ObjectPath } from '../utils/PathTracker';
import { EMPTY_PATH } from '../utils/PathTracker';
import { UNDEFINED_EXPRESSION } from '../values';
import ExportDefaultVariable from '../variables/ExportDefaultVariable';
import GlobalVariable from '../variables/GlobalVariable';
import LocalVariable from '../variables/LocalVariable';
import type Variable from '../variables/Variable';
import ChildScope from './ChildScope';
import type GlobalScope from './GlobalScope';

export default class ModuleScope extends ChildScope {
	declare parent: GlobalScope;

	constructor(
		parent: GlobalScope,
		context: AstContext,
		private readonly importDescriptions: Map<string, ImportDescription>
	) {
		super(parent, context);
		this.variables.set(
			'this',
			new LocalVariable('this', null, UNDEFINED_EXPRESSION, EMPTY_PATH, context, 'other')
		);
	}

	addDeclaration(
		identifier: Identifier,
		context: AstContext,
		init: ExpressionEntity,
		destructuredInitPath: ObjectPath,
		kind: VariableKind
	): LocalVariable {
		if (this.importDescriptions.has(identifier.name)) {
			context.error(logRedeclarationError(identifier.name), identifier.start);
		}
		return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
	}