Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions packages/pyright-internal/src/analyzer/codeFlowEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
ClassType,
combineTypes,
FunctionType,
isAnyOrUnknown,
isClass,
isClassInstance,
isFunction,
Expand All @@ -59,6 +60,7 @@ import {
isTypeSame,
isTypeVar,
isTypeVarTuple,
isUnion,
maxTypeRecursionCount,
NeverType,
OverloadedType,
Expand Down Expand Up @@ -1772,17 +1774,24 @@ export function getCodeFlowEngine(
const callTypeResult = evaluator.getTypeOfExpression(node.d.leftExpr, EvalFlags.CallBaseDefaults);
const callType = callTypeResult.type;

doForEachSubtype(callType, (callSubtype) => {
const callSubtypes = isUnion(callType) ? callType.priv.subtypes : [callType];
Comment thread
bschnurr marked this conversation as resolved.
for (let callSubtype of callSubtypes) {
// Track the number of subtypes we've examined.
subtypeCount++;

// Any or Unknown can never establish a guaranteed NoReturn result, so any
// union containing either is immediately a negative answer.
if (isAnyOrUnknown(callSubtype)) {
return false;
}

if (isInstantiableClass(callSubtype)) {
// Does the class have a custom metaclass that implements a `__call__` method?
// If so, it will be called instead of `__init__` or `__new__`. We'll assume
// in this case that the __call__ method is not a NoReturn type.
const metaclassCallResult = getBoundCallMethod(evaluator, node, callSubtype);
if (metaclassCallResult) {
return;
continue;
}

const newMethodResult = getBoundNewMethod(evaluator, node, callSubtype);
Expand Down Expand Up @@ -1839,7 +1848,7 @@ export function getCodeFlowEngine(
}
}
}
});
}

// The call is considered NoReturn if all subtypes evaluate to NoReturn.
const callIsNoReturn = subtypeCount > 0 && noReturnTypeCount === subtypeCount;
Expand Down
10 changes: 9 additions & 1 deletion packages/pyright-internal/src/tests/samples/unreachable1.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
import sys
from abc import abstractmethod
from typing import NoReturn
from typing import Callable, NoReturn


def func1():
Expand Down Expand Up @@ -92,6 +92,14 @@ def func9():
return 3


def func9_1(noreturn_func: Callable[[], NoReturn], unknown_func, flag: bool):
Comment thread
bschnurr marked this conversation as resolved.
callback = noreturn_func if flag else unknown_func
callback()

# This should not be marked unreachable because the call target includes Unknown.
return 3


def func10():
e = OSError()
a1 = os.name == "nt" and None == e.errno
Expand Down
Loading