Repository: microsoft/TypeScript
File: src/services/completions.ts (TypeScript)

Code before:
                        if (type.isNullableType()) {
                            const canCorrectToQuestionDot =
                                isRightOfDot &&
                                !isRightOfQuestionDot &&
                                preferences.includeAutomaticOptionalChainCompletions !== false;

                            if (canCorrectToQuestionDot || isRightOfQuestionDot) {
                                type = type.getNonNullableType();
                                if (canCorrectToQuestionDot) {
                                    insertQuestionDot = true;
                                }
                            }
                        }
                        addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
                    }

                    return;
                }
            }
        }

        // GH#39946. Pulling on the type of a node inside of a function with a contextual `this` parameter can result in a circularity
        // if the `node` is part of the exprssion of a `yield` or `return`. This circularity doesn't exist at compile time because
        // we will check (and cache) the type of `this` *before* checking the type of the node.
        typeChecker.tryGetThisTypeAt(node, /*includeGlobalThis*/ false);
        let type = typeChecker.getTypeAtLocation(node).getNonOptionalType();

        if (!isTypeLocation) {
            let insertQuestionDot = false;
            if (type.isNullableType()) {
                const canCorrectToQuestionDot =
                    isRightOfDot &&
                    !isRightOfQuestionDot &&
                    preferences.includeAutomaticOptionalChainCompletions !== false;

                if (canCorrectToQuestionDot || isRightOfQuestionDot) {
                    type = type.getNonNullableType();
                    if (canCorrectToQuestionDot) {
                        insertQuestionDot = true;
                    }
                }
            }
            addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
        }
        else if (isInTypeQuery(node)) {
            addTypeProperties(type.getNonNullableType(), /*insertAwait*/ false, /*insertQuestionDot*/ false);
        }
    }

    function addTypeProperties(type: Type, insertAwait: boolean, insertQuestionDot: boolean): void {
        isNewIdentifierLocation = !!type.getStringIndexType();

Review comment (performance):
On second look here, is this going to end up being accidentally slow? The old code here only pulled at this if `!isTypeLocation`, but the new code always does it. Would it make more sense to only do this if one of the other two branches is going to be executed?

Code after:
                        if (type.isNullableType()) {
                            const canCorrectToQuestionDot =
                                isRightOfDot &&
                                !isRightOfQuestionDot &&
                                preferences.includeAutomaticOptionalChainCompletions !== false;

                            if (canCorrectToQuestionDot || isRightOfQuestionDot) {
                                type = type.getNonNullableType();
                                if (canCorrectToQuestionDot) {
                                    insertQuestionDot = true;
                                }
                            }
                        }
                        addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
                    }

                    return;
                }
            }
        }

        if (!isTypeLocation || isInTypeQuery(node)) {
            // GH#39946. Pulling on the type of a node inside of a function with a contextual `this` parameter can result in a circularity
            // if the `node` is part of the exprssion of a `yield` or `return`. This circularity doesn't exist at compile time because
            // we will check (and cache) the type of `this` *before* checking the type of the node.
            typeChecker.tryGetThisTypeAt(node, /*includeGlobalThis*/ false);
            let type = typeChecker.getTypeAtLocation(node).getNonOptionalType();

            if (!isTypeLocation) {
                let insertQuestionDot = false;
                if (type.isNullableType()) {
                    const canCorrectToQuestionDot =
                        isRightOfDot &&
                        !isRightOfQuestionDot &&
                        preferences.includeAutomaticOptionalChainCompletions !== false;

                    if (canCorrectToQuestionDot || isRightOfQuestionDot) {
                        type = type.getNonNullableType();
                        if (canCorrectToQuestionDot) {
                            insertQuestionDot = true;
                        }
                    }
                }
                addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
            }
            else {
                addTypeProperties(type.getNonNullableType(), /*insertAwait*/ false, /*insertQuestionDot*/ false);
            }
        }
    }