Skip to content

Commit

Permalink
Added logic to detect illegal use of the symbol Any. This addresses #…
Browse files Browse the repository at this point in the history
  • Loading branch information
erictraut committed Oct 13, 2023
1 parent 4956810 commit 7502a99
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 3 deletions.
12 changes: 9 additions & 3 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15355,7 +15355,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
const assignedName = nameNode.value;

if (assignedName === 'Any') {
return AnyType.create();
return AnyType.createSpecialForm();
}

const specialTypes: Map<string, AliasMapEntry> = new Map([
Expand Down Expand Up @@ -15880,6 +15880,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
argType = removeUnbound(argType);
}

// Any is allowed as a base class. Remove its "special form" flag to avoid
// false positive errors.
if (isAny(argType) && TypeBase.isSpecialForm(argType)) {
argType = AnyType.create();
}

if (!isAnyOrUnknown(argType) && !isUnbound(argType)) {
if (isMetaclassInstance(argType)) {
assert(isClassInstance(argType));
Expand Down Expand Up @@ -22561,7 +22567,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
return true;
}

if (isAnyOrUnknown(srcType)) {
if (isAnyOrUnknown(srcType) && !TypeBase.isSpecialForm(srcType)) {
const targetTypeVarContext =
(flags & AssignTypeFlags.ReverseTypeVarMatching) === 0 ? destTypeVarContext : srcTypeVarContext;
if (targetTypeVarContext) {
Expand Down Expand Up @@ -22943,7 +22949,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
);
}
}
} else if (isAnyOrUnknown(concreteSrcType)) {
} else if (isAnyOrUnknown(concreteSrcType) && !TypeBase.isSpecialForm(concreteSrcType)) {
return (flags & AssignTypeFlags.OverloadOverlapCheck) === 0;
} else if (isUnion(concreteSrcType)) {
return assignType(
Expand Down
4 changes: 4 additions & 0 deletions packages/pyright-internal/src/analyzer/typeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,10 @@ export function convertToInstance(type: Type, includeSubclasses = true): Type {
}
break;
}

case TypeCategory.Any: {
return AnyType.convertToInstance(subtype);
}
}

return subtype;
Expand Down
22 changes: 22 additions & 0 deletions packages/pyright-internal/src/analyzer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2120,6 +2120,12 @@ export interface AnyType extends TypeBase {
}

export namespace AnyType {
const _anyInstanceSpecialForm: AnyType = {
category: TypeCategory.Any,
isEllipsis: false,
flags: TypeFlags.Instance | TypeFlags.Instantiable | TypeFlags.SpecialForm,
};

const _anyInstance: AnyType = {
category: TypeCategory.Any,
isEllipsis: false,
Expand All @@ -2135,6 +2141,22 @@ export namespace AnyType {
export function create(isEllipsis = false) {
return isEllipsis ? _ellipsisInstance : _anyInstance;
}

export function createSpecialForm() {
return _anyInstanceSpecialForm;
}
}

export namespace AnyType {
export function convertToInstance(type: AnyType): AnyType {
// Remove the "special form" flag if it's set. Otherwise
// simply return the existing type.
if (TypeBase.isSpecialForm(type)) {
return AnyType.create();
}

return type;
}
}

// References a single condition associated with a constrained TypeVar.
Expand Down
36 changes: 36 additions & 0 deletions packages/pyright-internal/src/tests/samples/any1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This sample tests certain uses of Any that should be flagged as illegal.

from typing import Any, cast
import typing


isinstance(0, Any)
isinstance(0, typing.Any)

v1 = cast(Any, 0)
v2 = cast(typing.Any, 0)


class A(Any):
...


class B(typing.Any):
...


# This should generate an error because Any is not callable.
Any()

# This should generate an error because Any is not callable.
typing.Any()


def func1() -> int:
# This should generate an error because Any cannot be used as a value.
return Any


def func2() -> int:
# This should generate an error because Any cannot be used as a value.
return typing.Any
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/tests/typeEvaluator4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1292,3 +1292,9 @@ test('Del2', () => {

TestUtils.validateResults(analysisResults, 2);
});

test('Any1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['any1.py']);

TestUtils.validateResults(analysisResults, 4);
});

0 comments on commit 7502a99

Please sign in to comment.