Change:
host: IExtensionsActivatorHost, @ILogService private readonly _logService: ILogService ) { <del> this._isDisposed = false; </del> this._registry = registry; this._resolvedExtensionsSet = new Set<string>(); resolvedExtensions.forEach((extensionId) => this._resolvedExtensionsSet.add(ExtensionIdentifier.toKey(extensionId))); this._externalExtensionsMap = new Map<string, ExtensionIdentifier>(); externalExtensions.forEach((extensionId) => this._externalExtensionsMap.set(ExtensionIdentifier.toKey(extensionId), extensionId)); this._host = host; <del> this._activatingExtensions = new Map<string, Promise<void>>(); this._activatedExtensions = new Map<string, ActivatedExtension>(); </del> <ins> this._operations = new Map<string, ActivationOperation>(); </ins> this._alreadyActivatedEvents = Object.create(null); } public dispose(): void { <del> this._isDisposed = true; </del> <ins> for (const [_, op] of this._operations) { op.dispose(); } </ins> } public isActivated(extensionId: ExtensionIdentifier): boolean { <del> const extensionKey = ExtensionIdentifier.toKey(extensionId); return this._activatedExtensions.has(extensionKey); </del> <ins> const op = this._operations.get(ExtensionIdentifier.toKey(extensionId)); return Boolean(op && op.value); </ins> } public getActivatedExtension(extensionId: ExtensionIdentifier): ActivatedExtension { <del> const extensionKey = ExtensionIdentifier.toKey(extensionId); const activatedExtension = this._activatedExtensions.get(extensionKey); if (!activatedExtension) { throw new Error('Extension `' + extensionId.value + '` is not known or not activated'); </del> <ins> const op = this._operations.get(ExtensionIdentifier.toKey(extensionId)); if (!op || !op.value) { throw new Error(`Extension '${extensionId.value}' is not known or not activated`); </ins> } <del> return activatedExtension; </del> <ins> return op.value; </ins> } <del> public activateByEvent(activationEvent: string, startup: boolean): Promise<void> { </del> <ins> public async activateByEvent(activationEvent: string, startup: boolean): Promise<void> { </ins> if (this._alreadyActivatedEvents[activationEvent]) { <del> return NO_OP_VOID_PROMISE; </del> <ins> return; </ins> } const activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent); <del> return this._activateExtensions(activateExtensions.map(e => ({ </del> <ins> await this._activateExtensions(activateExtensions.map(e => ({ </ins> id: e.identifier, reason: { startup, extensionId: e.identifier, activationEvent } <del> }))).then(() => { this._alreadyActivatedEvents[activationEvent] = true; }); </del> <ins> }))); this._alreadyActivatedEvents[activationEvent] = true; </ins> } public activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> { const desc = this._registry.getExtensionDescription(extensionId); if (!desc) { <del> throw new Error('Extension `' + extensionId + '` is not known'); </del> <ins> throw new Error(`Extension '${extensionId}' is not known`); </ins> } <ins> return this._activateExtensions([{ id: desc.identifier, reason }]); } </ins> <del> return this._activateExtensions([{ id: desc.identifier, reason }]); </del> <ins> private async _activateExtensions(extensions: ActivationIdAndReason[]): Promise<void> { const operations = extensions .filter((p) => !this.isActivated(p.id)) .map(ext => this._handleActivationRequest(ext)); await Promise.all(operations.map(op => op.wait())); </ins> } /** * Handle semantics related to dependencies for `currentExtension`. <del> * semantics: `redExtensions` must wait for `greenExtensions`. </del> <ins> * We don't need to worry about dependency loops because they are handled by the registry. </ins> */ <del> private _handleActivateRequest(currentActivation: ActivationIdAndReason, greenExtensions: { [id: string]: ActivationIdAndReason }, redExtensions: ActivationIdAndReason[]): void { </del> <ins> private _handleActivationRequest(currentActivation: ActivationIdAndReason): ActivationOperation { if (this._operations.has(ExtensionIdentifier.toKey(currentActivation.id))) { return this._operations.get(ExtensionIdentifier.toKey(currentActivation.id))!; } </ins> if (this._externalExtensionsMap.has(ExtensionIdentifier.toKey(currentActivation.id))) { <del> greenExtensions[ExtensionIdentifier.toKey(currentActivation.id)] = currentActivation; return; </del> <ins> return this._createAndSaveOperation(currentActivation, null, [], null); </ins> } const currentExtension = this._registry.getExtensionDescription(currentActivation.id); if (!currentExtension) { // Error condition 0: unknown extension const error = new Error(`Cannot activate unknown extension '${currentActivation.id.value}'`); <ins> const result = this._createAndSaveOperation(currentActivation, null, [], new FailedExtension(error)); </ins> this._host.onExtensionActivationError( currentActivation.id, error, new MissingExtensionDependency(currentActivation.id.value) ); <del> this._activatedExtensions.set(ExtensionIdentifier.toKey(currentActivation.id), new FailedExtension(error)); return; </del> <ins> return result; </ins> } <ins> const deps: ActivationOperation[] = []; </ins> const depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies); <del> let currentExtensionGetsGreenLight = true; for (let j = 0, lenJ = depIds.length; j < lenJ; j++) { const depId = depIds[j]; </del> <ins> for (const depId of depIds) { </ins> if (this._resolvedExtensionsSet.has(ExtensionIdentifier.toKey(depId))) { // This dependency is already resolved continue; } <del> const dep = this._activatedExtensions.get(ExtensionIdentifier.toKey(depId)); if (dep && !dep.activationFailed) { // the dependency is already activated OK </del> <ins> const dep = this._operations.get(ExtensionIdentifier.toKey(depId)); if (dep) { deps.push(dep); </ins> continue; } <del> if (dep && dep.activationFailed) { // Error condition 2: a dependency has already failed activation const currentExtensionFriendlyName = currentExtension.displayName || currentExtension.identifier.value; const depDesc = this._registry.getExtensionDescription(depId); const depFriendlyName = (depDesc ? depDesc.displayName || depId : depId); const error = new Error(`Cannot activate the '${currentExtensionFriendlyName}' extension because its dependency '${depFriendlyName}' failed to activate`); (<any>error).detail = dep.activationFailedError; this._host.onExtensionActivationError( currentExtension.identifier, error, null ); this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error)); return; } </del> if (this._externalExtensionsMap.has(ExtensionIdentifier.toKey(depId))) { // must first wait for the dependency to activate <del> currentExtensionGetsGreenLight = false; greenExtensions[ExtensionIdentifier.toKey(depId)] = { </del> <ins> deps.push(this._handleActivationRequest({ </ins> id: this._externalExtensionsMap.get(ExtensionIdentifier.toKey(depId))!, reason: currentActivation.reason <del> }; </del> <ins> })); </ins> continue; }

Discussion:
<!-- Do Not Delete This! bugreporttemplate --<!-- Please read our Rules of Conduct: --<!-- Read our guide about submitting issues: --<!-- Search existing issues to avoid creating duplicates. --<!-- Test using the latest Insiders build to see if your issue has already been fixed: --<!-- Instead of creating your report here, use 'Report Issue' from the 'Help' menu in VS Code to pre-fill useful information. --<!-- Launch with to check. --Does this issue occur when all extensions are disabled?: No <!-- If you answered No above, use 'Help: Start Extension Bisect' from Command Palette to try to identify the cause. --<!-- Issues caused by an extension need to be reported directly to the extension publisher. The 'Help Report Issue' dialog can assist with this. --- VS Code Version: 1.65.0 OS Version: Fedora 35 Steps to Reproduce: extension (v11.10.0) vscode, git extension is not initialized and restart, git extension works again With vscode-icons disabled With vscode-icons enabled
Reproduces with the following extension: : :