Fixed a recent regression that resulted in unsolved type arguments when a "bare" generic class (like dict) is passed as an argument to a function that accepts a type[T]. This addresses #5392. (#5494)

Co-authored-by: Eric Traut <erictr@microsoft.com>
This commit is contained in:
Eric Traut 2023-07-13 17:39:33 +02:00 committed by GitHub
parent 1fa0a4f1cc
commit bb60966327
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 2 deletions

View File

@ -397,8 +397,14 @@ export function assignTypeToTypeVar(
// If the source is a class that is missing type arguments, fill
// in missing type arguments with Unknown.
if ((flags & AssignTypeFlags.AllowUnspecifiedTypeArguments) === 0) {
if (isClass(adjSrcType) && adjSrcType.includeSubclasses) {
adjSrcType = specializeWithDefaultTypeArgs(adjSrcType);
if (isClass(adjSrcType)) {
// Skip this if the source is a concrete class and the dest is
// not a type[T]. This combination is used for class decorators
// such as dataclass_transform, and we need to retain the original
// unspecialized class in this case.
if (adjSrcType.includeSubclasses || TypeBase.isInstantiable(destType)) {
adjSrcType = specializeWithDefaultTypeArgs(adjSrcType);
}
}
}

View File

@ -0,0 +1,23 @@
# This sample tests that the assignment of an instantiable generic class
# without supplied type arguments is given default type arguments (typically
# Unknown) when the TypeVar is solved.
from typing import Any, TypeVar, reveal_type
T = TypeVar("T")
def deco1(t: type[T], val: Any) -> T:
return val
v1 = deco1(dict, {"foo": "bar"})
reveal_type(v1, expected_text="dict[Unknown, Unknown]")
def deco2(t: T, val: Any) -> T:
return val
v2 = deco2(dict, {"foo": "bar"})
reveal_type(v2, expected_text="type[dict[Unknown, Unknown]]")

View File

@ -653,6 +653,12 @@ test('Solver26', () => {
TestUtils.validateResults(analysisResults, 0);
});
test('Solver27', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['solver27.py']);
TestUtils.validateResults(analysisResults, 0);
});
test('SolverScoring1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['solverScoring1.py']);