зеркало из https://github.com/microsoft/pyright.git
Removed support for python-2 raise statements with comma-delimited operands. (#8915)
Removed redundant logic for checking exception type in `raise x from y` statements. Changed behavior of raise evaluation logic to allow type of exception to be `Never`. This addresses #8911.
This commit is contained in:
Родитель
d841fb9e91
Коммит
05435baad8
|
@ -1456,14 +1456,11 @@ export class Binder extends ParseTreeWalker {
|
|||
this._targetFunctionDeclaration.raiseStatements.push(node);
|
||||
}
|
||||
|
||||
if (node.d.typeExpression) {
|
||||
this.walk(node.d.typeExpression);
|
||||
if (node.d.expr) {
|
||||
this.walk(node.d.expr);
|
||||
}
|
||||
if (node.d.valueExpression) {
|
||||
this.walk(node.d.valueExpression);
|
||||
}
|
||||
if (node.d.tracebackExpression) {
|
||||
this.walk(node.d.tracebackExpression);
|
||||
if (node.d.fromExpr) {
|
||||
this.walk(node.d.fromExpr);
|
||||
}
|
||||
|
||||
this._finallyTargets.forEach((target) => {
|
||||
|
|
|
@ -1093,46 +1093,12 @@ export class Checker extends ParseTreeWalker {
|
|||
}
|
||||
|
||||
override visitRaise(node: RaiseNode): boolean {
|
||||
this._evaluator.verifyRaiseExceptionType(node);
|
||||
if (node.d.expr) {
|
||||
this._evaluator.verifyRaiseExceptionType(node.d.expr);
|
||||
}
|
||||
|
||||
if (node.d.valueExpression) {
|
||||
const baseExceptionType = this._evaluator.getBuiltInType(node, 'BaseException') as ClassType;
|
||||
const exceptionType = this._evaluator.getType(node.d.valueExpression);
|
||||
|
||||
// Validate that the argument of "raise" is an exception object or None.
|
||||
if (exceptionType && baseExceptionType && isInstantiableClass(baseExceptionType)) {
|
||||
const diagAddendum = new DiagnosticAddendum();
|
||||
|
||||
doForEachSubtype(exceptionType, (subtype) => {
|
||||
subtype = this._evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
||||
|
||||
if (!isAnyOrUnknown(subtype) && !isNoneInstance(subtype)) {
|
||||
if (isClass(subtype)) {
|
||||
if (!derivesFromClassRecursive(subtype, baseExceptionType, /* ignoreUnknown */ false)) {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: this._evaluator.printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: this._evaluator.printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!diagAddendum.isEmpty()) {
|
||||
this._evaluator.addDiagnostic(
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
LocMessage.expectedExceptionObj() + diagAddendum.getString(),
|
||||
node.d.valueExpression
|
||||
);
|
||||
}
|
||||
}
|
||||
if (node.d.fromExpr) {
|
||||
this._evaluator.verifyRaiseExceptionType(node.d.fromExpr);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1862,9 +1862,9 @@ export function getCodeFlowEngine(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (simpleStatement.nodeType === ParseNodeType.Raise && simpleStatement.d.typeExpression) {
|
||||
if (simpleStatement.nodeType === ParseNodeType.Raise && simpleStatement.d.expr) {
|
||||
// Check for a raising about 'NotImplementedError' or a subtype thereof.
|
||||
const exceptionType = evaluator.getType(simpleStatement.d.typeExpression);
|
||||
const exceptionType = evaluator.getType(simpleStatement.d.expr);
|
||||
|
||||
if (
|
||||
exceptionType &&
|
||||
|
|
|
@ -272,7 +272,7 @@ export function getChildNodes(node: ParseNode): (ParseNode | undefined)[] {
|
|||
return [node.d.expr];
|
||||
|
||||
case ParseNodeType.Raise:
|
||||
return [node.d.typeExpression, node.d.valueExpression, node.d.tracebackExpression];
|
||||
return [node.d.expr, node.d.fromExpr];
|
||||
|
||||
case ParseNodeType.Return:
|
||||
return [node.d.expr];
|
||||
|
|
|
@ -68,7 +68,6 @@ import {
|
|||
ParameterNode,
|
||||
ParseNode,
|
||||
ParseNodeType,
|
||||
RaiseNode,
|
||||
SetNode,
|
||||
SliceNode,
|
||||
StringListNode,
|
||||
|
@ -4343,87 +4342,80 @@ export function createTypeEvaluator(
|
|||
}
|
||||
}
|
||||
|
||||
function verifyRaiseExceptionType(node: RaiseNode) {
|
||||
function verifyRaiseExceptionType(node: ExpressionNode) {
|
||||
const baseExceptionType = getBuiltInType(node, 'BaseException');
|
||||
const exceptionType = getTypeOfExpression(node).type;
|
||||
|
||||
if (node.d.typeExpression) {
|
||||
const exceptionType = getTypeOfExpression(node.d.typeExpression).type;
|
||||
// Validate that the argument of "raise" is an exception object or class.
|
||||
// If it is a class, validate that the class's constructor accepts zero
|
||||
// arguments.
|
||||
if (exceptionType && baseExceptionType && isInstantiableClass(baseExceptionType)) {
|
||||
const diag = new DiagnosticAddendum();
|
||||
|
||||
// Validate that the argument of "raise" is an exception object or class.
|
||||
// If it is a class, validate that the class's constructor accepts zero
|
||||
// arguments.
|
||||
if (exceptionType && baseExceptionType && isInstantiableClass(baseExceptionType)) {
|
||||
const diagAddendum = new DiagnosticAddendum();
|
||||
doForEachSubtype(exceptionType, (subtype) => {
|
||||
const concreteSubtype = makeTopLevelTypeVarsConcrete(subtype);
|
||||
|
||||
doForEachSubtype(exceptionType, (subtype) => {
|
||||
const concreteSubtype = makeTopLevelTypeVarsConcrete(subtype);
|
||||
if (isAnyOrUnknown(concreteSubtype) || isNever(concreteSubtype) || isNoneInstance(concreteSubtype)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAnyOrUnknown(concreteSubtype)) {
|
||||
if (isInstantiableClass(concreteSubtype) && concreteSubtype.priv.literalValue === undefined) {
|
||||
if (
|
||||
!derivesFromClassRecursive(
|
||||
concreteSubtype,
|
||||
baseExceptionType,
|
||||
/* ignoreUnknown */ false
|
||||
)
|
||||
) {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
let callResult: CallResult | undefined;
|
||||
suppressDiagnostics(node.d.typeExpression!, () => {
|
||||
callResult = validateConstructorArgs(
|
||||
evaluatorInterface,
|
||||
node.d.typeExpression!,
|
||||
[],
|
||||
concreteSubtype,
|
||||
/* skipUnknownArgCheck */ false,
|
||||
/* inferenceContext */ undefined
|
||||
);
|
||||
});
|
||||
if (isInstantiableClass(concreteSubtype) && concreteSubtype.priv.literalValue === undefined) {
|
||||
if (!derivesFromClassRecursive(concreteSubtype, baseExceptionType, /* ignoreUnknown */ false)) {
|
||||
diag.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
let callResult: CallResult | undefined;
|
||||
suppressDiagnostics(node, () => {
|
||||
callResult = validateConstructorArgs(
|
||||
evaluatorInterface,
|
||||
node,
|
||||
[],
|
||||
concreteSubtype,
|
||||
/* skipUnknownArgCheck */ false,
|
||||
/* inferenceContext */ undefined
|
||||
);
|
||||
});
|
||||
|
||||
if (callResult && callResult.argumentErrors) {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeNotInstantiable().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (isClassInstance(concreteSubtype)) {
|
||||
if (
|
||||
!derivesFromClassRecursive(
|
||||
ClassType.cloneAsInstantiable(concreteSubtype),
|
||||
baseExceptionType,
|
||||
/* ignoreUnknown */ false
|
||||
)
|
||||
) {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
diagAddendum.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
if (callResult && callResult.argumentErrors) {
|
||||
diag.addMessage(
|
||||
LocMessage.exceptionTypeNotInstantiable().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!diagAddendum.isEmpty()) {
|
||||
addDiagnostic(
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
LocMessage.expectedExceptionClass() + diagAddendum.getString(),
|
||||
node.d.typeExpression
|
||||
} else if (isClassInstance(concreteSubtype)) {
|
||||
if (
|
||||
!derivesFromClassRecursive(
|
||||
ClassType.cloneAsInstantiable(concreteSubtype),
|
||||
baseExceptionType,
|
||||
/* ignoreUnknown */ false
|
||||
)
|
||||
) {
|
||||
diag.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
diag.addMessage(
|
||||
LocMessage.exceptionTypeIncorrect().format({
|
||||
type: printType(subtype),
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!diag.isEmpty()) {
|
||||
addDiagnostic(
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
LocMessage.expectedExceptionClass() + diag.getString(),
|
||||
node
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19242,10 +19234,10 @@ export function createTypeEvaluator(
|
|||
}
|
||||
|
||||
for (const raiseStatement of functionDecl.raiseStatements) {
|
||||
if (!raiseStatement.d.typeExpression || raiseStatement.d.valueExpression) {
|
||||
if (!raiseStatement.d.expr || raiseStatement.d.fromExpr) {
|
||||
return false;
|
||||
}
|
||||
const raiseType = getTypeOfExpression(raiseStatement.d.typeExpression).type;
|
||||
const raiseType = getTypeOfExpression(raiseStatement.d.expr).type;
|
||||
const classType = isInstantiableClass(raiseType)
|
||||
? raiseType
|
||||
: isClassInstance(raiseType)
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
ParamCategory,
|
||||
ParameterNode,
|
||||
ParseNode,
|
||||
RaiseNode,
|
||||
StringNode,
|
||||
} from '../parser/parseNodes';
|
||||
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
||||
|
@ -551,7 +550,7 @@ export interface TypeEvaluator {
|
|||
) => Type;
|
||||
|
||||
getExpectedType: (node: ExpressionNode) => ExpectedTypeResult | undefined;
|
||||
verifyRaiseExceptionType: (node: RaiseNode) => void;
|
||||
verifyRaiseExceptionType: (node: ExpressionNode) => void;
|
||||
verifyDeleteExpression: (node: ExpressionNode) => void;
|
||||
validateOverloadedArgTypes: (
|
||||
errorNode: ExpressionNode,
|
||||
|
|
|
@ -2314,9 +2314,8 @@ export namespace ReturnNode {
|
|||
|
||||
export interface RaiseNode extends ParseNodeBase<ParseNodeType.Raise> {
|
||||
d: {
|
||||
typeExpression?: ExpressionNode | undefined;
|
||||
valueExpression?: ExpressionNode | undefined;
|
||||
tracebackExpression?: ExpressionNode | undefined;
|
||||
expr?: ExpressionNode | undefined;
|
||||
fromExpr?: ExpressionNode | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2821,29 +2821,14 @@ export class Parser {
|
|||
|
||||
const raiseNode = RaiseNode.create(raiseToken);
|
||||
if (!this._isNextTokenNeverExpression()) {
|
||||
raiseNode.d.typeExpression = this._parseTestExpression(/* allowAssignmentExpression */ true);
|
||||
raiseNode.d.typeExpression.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.typeExpression);
|
||||
raiseNode.d.expr = this._parseTestExpression(/* allowAssignmentExpression */ true);
|
||||
raiseNode.d.expr.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.expr);
|
||||
|
||||
if (this._consumeTokenIfKeyword(KeywordType.From)) {
|
||||
raiseNode.d.valueExpression = this._parseTestExpression(/* allowAssignmentExpression */ true);
|
||||
raiseNode.d.valueExpression.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.valueExpression);
|
||||
} else {
|
||||
if (this._consumeTokenIfType(TokenType.Comma)) {
|
||||
// Handle the Python 2.x variant
|
||||
raiseNode.d.valueExpression = this._parseTestExpression(/* allowAssignmentExpression */ true);
|
||||
raiseNode.d.valueExpression.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.valueExpression);
|
||||
|
||||
if (this._consumeTokenIfType(TokenType.Comma)) {
|
||||
raiseNode.d.tracebackExpression = this._parseTestExpression(
|
||||
/* allowAssignmentExpression */ true
|
||||
);
|
||||
raiseNode.d.tracebackExpression.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.tracebackExpression);
|
||||
}
|
||||
}
|
||||
raiseNode.d.fromExpr = this._parseTestExpression(/* allowAssignmentExpression */ true);
|
||||
raiseNode.d.fromExpr.parent = raiseNode;
|
||||
extendRange(raiseNode, raiseNode.d.fromExpr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -396,7 +396,7 @@ test('ParamType1', () => {
|
|||
test('Python2', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['python2.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 6);
|
||||
TestUtils.validateResults(analysisResults, 7);
|
||||
});
|
||||
|
||||
test('InconsistentSpaceTab1', () => {
|
||||
|
|
|
@ -26,6 +26,6 @@ a = `b`
|
|||
def foo(a, (b, c), d):
|
||||
pass
|
||||
|
||||
# This should generate an error.
|
||||
# This should generate two errors.
|
||||
raise NameError, a > 4, a < 4
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче