@zzzen/pyright-internal 1.2.0-dev.20261101 → 1.2.0-dev.20261108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer/binder.js +9 -3
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/constructorTransform.js +12 -0
- package/dist/analyzer/constructorTransform.js.map +1 -1
- package/dist/analyzer/constructors.d.ts +1 -1
- package/dist/analyzer/constructors.js +1 -1
- package/dist/analyzer/constructors.js.map +1 -1
- package/dist/analyzer/decorators.d.ts +1 -1
- package/dist/analyzer/decorators.js.map +1 -1
- package/dist/analyzer/functionTransform.d.ts +5 -0
- package/dist/analyzer/functionTransform.js +6 -3
- package/dist/analyzer/functionTransform.js.map +1 -1
- package/dist/analyzer/missingBindingMetadata.d.ts +6 -0
- package/dist/analyzer/missingBindingMetadata.js +22 -0
- package/dist/analyzer/missingBindingMetadata.js.map +1 -0
- package/dist/analyzer/namedTuples.d.ts +4 -1
- package/dist/analyzer/namedTuples.js +1 -0
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/patternMatching.d.ts +5 -1
- package/dist/analyzer/patternMatching.js +3 -0
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/program.d.ts +3 -0
- package/dist/analyzer/program.js +71 -1
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/tuples.d.ts +1 -1
- package/dist/analyzer/tuples.js.map +1 -1
- package/dist/analyzer/typeCacheUtils.d.ts +1 -0
- package/dist/analyzer/typeCacheUtils.js +10 -0
- package/dist/analyzer/typeCacheUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.d.ts +15 -0
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js +98 -0
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js.map +1 -0
- package/dist/analyzer/typeEvaluator/classConstruction.d.ts +25 -0
- package/dist/analyzer/typeEvaluator/classConstruction.js +251 -0
- package/dist/analyzer/typeEvaluator/classConstruction.js.map +1 -0
- package/dist/analyzer/typeEvaluator/collectionInference.d.ts +41 -0
- package/dist/analyzer/typeEvaluator/collectionInference.js +695 -0
- package/dist/analyzer/typeEvaluator/collectionInference.js.map +1 -0
- package/dist/analyzer/typeEvaluator/diagnostics.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/diagnostics.js +198 -0
- package/dist/analyzer/typeEvaluator/diagnostics.js.map +1 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.d.ts +80 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.js +1126 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.js.map +1 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.d.ts +17 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js +370 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js.map +1 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.d.ts +81 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.js +1802 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.js +217 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.js.map +1 -0
- package/dist/analyzer/typeEvaluator/internals.d.ts +137 -0
- package/dist/analyzer/typeEvaluator/internals.js +10 -0
- package/dist/analyzer/typeEvaluator/internals.js.map +1 -0
- package/dist/analyzer/typeEvaluator/literalTypes.d.ts +3 -0
- package/dist/analyzer/typeEvaluator/literalTypes.js +52 -0
- package/dist/analyzer/typeEvaluator/literalTypes.js.map +1 -0
- package/dist/analyzer/typeEvaluator/memberResolution.d.ts +79 -0
- package/dist/analyzer/typeEvaluator/memberResolution.js +1007 -0
- package/dist/analyzer/typeEvaluator/memberResolution.js.map +1 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.d.ts +15 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.js +422 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.js +226 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.js.map +1 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.d.ts +39 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.js +1728 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.d.ts +2 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.js +36 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.d.ts +36 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.js +1320 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.d.ts +186 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js +1683 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.d.ts +48 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.js +756 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.js.map +1 -0
- package/dist/analyzer/typeEvaluator.d.ts +3 -31
- package/dist/analyzer/typeEvaluator.js +5033 -13761
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeGuards.d.ts +2 -2
- package/dist/analyzer/typeGuards.js +212 -1567
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typeUtils.js +6 -2
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typedDicts.js +111 -0
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/browser/browserConnection.d.ts +12 -0
- package/dist/browser/browserConnection.js +23 -0
- package/dist/browser/browserConnection.js.map +1 -0
- package/dist/browser/browserFileSystem.d.ts +73 -0
- package/dist/browser/browserFileSystem.js +578 -0
- package/dist/browser/browserFileSystem.js.map +1 -0
- package/dist/browser/browserHost.d.ts +4 -0
- package/dist/browser/browserHost.js +10 -0
- package/dist/browser/browserHost.js.map +1 -0
- package/dist/browser/browserProcess.d.ts +1 -0
- package/dist/browser/browserProcess.js +17 -0
- package/dist/browser/browserProcess.js.map +1 -0
- package/dist/browser/browserServer.d.ts +8 -0
- package/dist/browser/browserServer.js +32 -0
- package/dist/browser/browserServer.js.map +1 -0
- package/dist/browser/cancellation/common.d.ts +10 -0
- package/dist/browser/cancellation/common.js +114 -0
- package/dist/browser/cancellation/common.js.map +1 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.d.ts +5 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.js +37 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.js.map +1 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.d.ts +7 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.js +32 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.js.map +1 -0
- package/dist/browser/worker.d.ts +1 -0
- package/dist/browser/worker.js +33 -0
- package/dist/browser/worker.js.map +1 -0
- package/dist/pyrightServer.d.ts +34 -0
- package/dist/pyrightServer.js +239 -0
- package/dist/pyrightServer.js.map +1 -0
- package/dist/server.d.ts +3 -23
- package/dist/server.js +12 -232
- package/dist/server.js.map +1 -1
- package/dist/tests/benchmarks/typeInferenceComparison.d.ts +1 -0
- package/dist/tests/benchmarks/typeInferenceComparison.js +1235 -0
- package/dist/tests/benchmarks/typeInferenceComparison.js.map +1 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.d.ts +1 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.js +53 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.js.map +1 -0
- package/dist/tests/browserCancellation.test.d.ts +1 -0
- package/dist/tests/browserCancellation.test.js +63 -0
- package/dist/tests/browserCancellation.test.js.map +1 -0
- package/dist/tests/browserServer.test.d.ts +1 -0
- package/dist/tests/browserServer.test.js +177 -0
- package/dist/tests/browserServer.test.js.map +1 -0
- package/dist/tests/constraintSolver.test.js +45 -0
- package/dist/tests/constraintSolver.test.js.map +1 -1
- package/dist/tests/mypyPrimerAnalysis.test.js +15 -1
- package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
- package/dist/tests/typeCacheUtils.test.js +46 -0
- package/dist/tests/typeCacheUtils.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +75 -0
- package/dist/tests/typeEvaluator1.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +4 -0
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +32 -0
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator7.test.js +394 -0
- package/dist/tests/typeEvaluator7.test.js.map +1 -1
- package/dist/tests/typeUtils.test.js +28 -0
- package/dist/tests/typeUtils.test.js.map +1 -1
- package/dist/typeServer/stubGenerator.js +136 -3
- package/dist/typeServer/stubGenerator.js.map +1 -1
- package/dist/typeServer/typeServerConversionUtils.js +13 -0
- package/dist/typeServer/typeServerConversionUtils.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,1320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* typeCompatibility.ts
|
|
4
|
+
* Copyright (c) Microsoft Corporation.
|
|
5
|
+
* Licensed under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* typeCompatibility implementation, using evaluator-owned dependencies and state.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createTypeCompatibility = createTypeCompatibility;
|
|
11
|
+
const collectionUtils_1 = require("../../common/collectionUtils");
|
|
12
|
+
const debug_1 = require("../../common/debug");
|
|
13
|
+
const diagnostic_1 = require("../../common/diagnostic");
|
|
14
|
+
const localize_1 = require("../../localization/localize");
|
|
15
|
+
const parameterUtils_1 = require("../parameterUtils");
|
|
16
|
+
const protocols_1 = require("../protocols");
|
|
17
|
+
const tuples_1 = require("../tuples");
|
|
18
|
+
const typedDicts_1 = require("../typedDicts");
|
|
19
|
+
const types_1 = require("../types");
|
|
20
|
+
const typeUtils_1 = require("../typeUtils");
|
|
21
|
+
// Checks assignability, accumulating constraints and diagnostics through evaluator callbacks.
|
|
22
|
+
function createTypeCompatibility(context) {
|
|
23
|
+
const { assignNamedParam, assignType, assignTypeArgs, evaluatorInterface, getEffectiveReturnType, inferVarianceForClass, isParamListOverlapOnlyByOmission, isTypeSubsumedByOtherType, makeTopLevelTypeVarsConcrete, printSrcDestTypes, printType, solveAndApplyConstraints, stripLiteralValue, typePromotions, } = context;
|
|
24
|
+
function assignClass(destType, srcType, diag, constraints, flags, recursionCount, reportErrorsUsingObjType) {
|
|
25
|
+
// If the source or dest types are partially evaluated (i.e. they are in the
|
|
26
|
+
// process of being constructed), assume they are assignable rather than risk
|
|
27
|
+
// emitting false positives.
|
|
28
|
+
if (types_1.ClassType.isHierarchyPartiallyEvaluated(destType) || types_1.ClassType.isHierarchyPartiallyEvaluated(srcType)) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
// Handle typed dicts. They also use a form of structural typing for type
|
|
32
|
+
// checking, as defined in PEP 589.
|
|
33
|
+
if (types_1.ClassType.isTypedDictClass(srcType)) {
|
|
34
|
+
if (types_1.ClassType.isTypedDictClass(destType) && !types_1.ClassType.isSameGenericClass(destType, srcType)) {
|
|
35
|
+
if (!(0, typedDicts_1.assignTypedDictToTypedDict)(evaluatorInterface, destType, srcType, diag, constraints, flags, recursionCount)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// If invariance is being enforced, the two TypedDicts must be assignable to each other.
|
|
39
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) !== 0) {
|
|
40
|
+
return (0, typedDicts_1.assignTypedDictToTypedDict)(evaluatorInterface, srcType, destType,
|
|
41
|
+
/* diag */ undefined,
|
|
42
|
+
/* constraints */ undefined, flags, recursionCount);
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// Handle some special cases where a TypedDict can act like
|
|
47
|
+
// a Mapping[str, T] or a dict[str, T].
|
|
48
|
+
if (types_1.ClassType.isBuiltIn(destType, 'Mapping')) {
|
|
49
|
+
const mappingValueType = (0, typedDicts_1.getTypedDictMappingEquivalent)(evaluatorInterface, srcType);
|
|
50
|
+
if (mappingValueType &&
|
|
51
|
+
context.prefetched?.mappingClass &&
|
|
52
|
+
(0, types_1.isInstantiableClass)(context.prefetched.mappingClass) &&
|
|
53
|
+
context.prefetched?.strClass &&
|
|
54
|
+
(0, types_1.isInstantiableClass)(context.prefetched.strClass)) {
|
|
55
|
+
srcType = types_1.ClassType.specialize(context.prefetched.mappingClass, [
|
|
56
|
+
types_1.ClassType.cloneAsInstance(context.prefetched.strClass),
|
|
57
|
+
mappingValueType,
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (types_1.ClassType.isBuiltIn(destType, ['dict', 'MutableMapping'])) {
|
|
62
|
+
const dictValueType = (0, typedDicts_1.getTypedDictDictEquivalent)(evaluatorInterface, srcType, recursionCount);
|
|
63
|
+
if (dictValueType &&
|
|
64
|
+
context.prefetched?.dictClass &&
|
|
65
|
+
(0, types_1.isInstantiableClass)(context.prefetched.dictClass) &&
|
|
66
|
+
context.prefetched.strClass &&
|
|
67
|
+
(0, types_1.isInstantiableClass)(context.prefetched.strClass)) {
|
|
68
|
+
srcType = types_1.ClassType.specialize(context.prefetched.dictClass, [
|
|
69
|
+
types_1.ClassType.cloneAsInstance(context.prefetched.strClass),
|
|
70
|
+
dictValueType,
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Handle special-case type promotions.
|
|
76
|
+
if (destType.priv.includePromotions) {
|
|
77
|
+
const promotionList = typePromotions.get(destType.shared.fullName);
|
|
78
|
+
if (promotionList &&
|
|
79
|
+
promotionList.some((srcName) => srcType.shared.mro.some((mroClass) => (0, types_1.isClass)(mroClass) && srcName === mroClass.shared.fullName))) {
|
|
80
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) === 0) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// A class value normally remains unspecialized so it can be subscripted.
|
|
86
|
+
// If every type parameter has an explicit default, apply those defaults
|
|
87
|
+
// when comparing it against a type specialization. Classes with defaultless
|
|
88
|
+
// parameters or defaults that resolve directly to Any or Unknown retain
|
|
89
|
+
// their unspecialized behavior, so they don't degrade inference.
|
|
90
|
+
if (types_1.TypeBase.isInstantiable(srcType) &&
|
|
91
|
+
srcType.props?.typeForm &&
|
|
92
|
+
!srcType.priv.typeArgs &&
|
|
93
|
+
!srcType.priv.includeSubclasses &&
|
|
94
|
+
srcType.shared.typeParams.length > 0 &&
|
|
95
|
+
srcType.shared.typeParams.every((typeParam) => typeParam.shared.isDefaultExplicit)) {
|
|
96
|
+
const specializedSrcType = (0, typeUtils_1.specializeWithDefaultTypeArgs)(srcType);
|
|
97
|
+
const specializedTypeArgs = specializedSrcType.priv.typeArgs ??
|
|
98
|
+
specializedSrcType.priv.tupleTypeArgs?.map((tupleTypeArg) => tupleTypeArg.type);
|
|
99
|
+
const hasGradualTypeArg = specializedTypeArgs?.some((typeArg) => !!(0, typeUtils_1.containsAnyOrUnknown)(typeArg, /* recurse */ false) ||
|
|
100
|
+
((0, types_1.isFunction)(typeArg) && types_1.FunctionType.isGradualCallableForm(typeArg)) ||
|
|
101
|
+
((0, types_1.isUnpackedClass)(typeArg) && !!(0, typeUtils_1.containsAnyOrUnknown)(typeArg, /* recurse */ true)));
|
|
102
|
+
if (hasGradualTypeArg === false) {
|
|
103
|
+
srcType = specializedSrcType;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Is it a structural type (i.e. a protocol)? If so, we need to
|
|
107
|
+
// perform a member-by-member check.
|
|
108
|
+
const inheritanceChain = [];
|
|
109
|
+
const isDerivedFrom = types_1.ClassType.isDerivedFrom(srcType, destType, inheritanceChain);
|
|
110
|
+
// Use the slow path for protocols if the dest doesn't explicitly
|
|
111
|
+
// derive from the source. We also need to use this path if we're
|
|
112
|
+
// testing to see if the metaclass matches the protocol.
|
|
113
|
+
if (types_1.ClassType.isProtocolClass(destType) && !isDerivedFrom) {
|
|
114
|
+
if (!(0, protocols_1.assignClassToProtocol)(evaluatorInterface, destType, types_1.ClassType.cloneAsInstance(srcType), diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
115
|
+
diag?.addMessage(localize_1.LocAddendum.protocolIncompatible().format({
|
|
116
|
+
sourceType: printType((0, typeUtils_1.convertToInstance)(srcType)),
|
|
117
|
+
destType: printType((0, typeUtils_1.convertToInstance)(destType)),
|
|
118
|
+
}));
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) === 0 || types_1.ClassType.isSameGenericClass(srcType, destType)) {
|
|
124
|
+
if (isDerivedFrom) {
|
|
125
|
+
(0, debug_1.assert)(inheritanceChain.length > 0);
|
|
126
|
+
if (assignClassWithTypeArgs(destType, srcType, inheritanceChain, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Everything is assignable to an object.
|
|
132
|
+
if (types_1.ClassType.isBuiltIn(destType, 'object')) {
|
|
133
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) === 0) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (diag) {
|
|
138
|
+
const destErrorType = reportErrorsUsingObjType ? types_1.ClassType.cloneAsInstance(destType) : destType;
|
|
139
|
+
const srcErrorType = reportErrorsUsingObjType ? types_1.ClassType.cloneAsInstance(srcType) : srcType;
|
|
140
|
+
let destErrorTypeText = printType(destErrorType);
|
|
141
|
+
let srcErrorTypeText = printType(srcErrorType);
|
|
142
|
+
// If the text is the same, use the fully-qualified name rather than the short name.
|
|
143
|
+
if (destErrorTypeText === srcErrorTypeText && destType.shared.fullName && srcType.shared.fullName) {
|
|
144
|
+
destErrorTypeText = destType.shared.fullName;
|
|
145
|
+
srcErrorTypeText = srcType.shared.fullName;
|
|
146
|
+
}
|
|
147
|
+
diag?.addMessage(localize_1.LocAddendum.typeIncompatible().format({
|
|
148
|
+
sourceType: srcErrorTypeText,
|
|
149
|
+
destType: destErrorTypeText,
|
|
150
|
+
}));
|
|
151
|
+
// Tell the user about the disableBytesTypePromotions if that is involved.
|
|
152
|
+
if (types_1.ClassType.isBuiltIn(destType, 'bytes')) {
|
|
153
|
+
const promotions = typePromotions.get(destType.shared.fullName);
|
|
154
|
+
if (promotions && promotions.some((name) => name === srcType.shared.fullName)) {
|
|
155
|
+
diag?.addMessage(localize_1.LocAddendum.bytesTypePromotions());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
function assignClassWithTypeArgs(destType, srcType, inheritanceChain, diag, constraints, flags, recursionCount) {
|
|
162
|
+
let curSrcType = srcType;
|
|
163
|
+
let prevSrcType;
|
|
164
|
+
inferVarianceForClass(destType);
|
|
165
|
+
// If we're enforcing invariance, literal types must match.
|
|
166
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) !== 0) {
|
|
167
|
+
const srcIsLiteral = (0, typeUtils_1.isLiteralLikeType)(srcType);
|
|
168
|
+
const destIsLiteral = (0, typeUtils_1.isLiteralLikeType)(destType);
|
|
169
|
+
if (srcIsLiteral !== destIsLiteral) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (let ancestorIndex = inheritanceChain.length - 1; ancestorIndex >= 0; ancestorIndex--) {
|
|
174
|
+
const ancestorType = inheritanceChain[ancestorIndex];
|
|
175
|
+
// If we've hit an "unknown", all bets are off, and we need to assume
|
|
176
|
+
// that the type is assignable. If the destType is marked "@final",
|
|
177
|
+
// we should be able to assume that it's not assignable, but we can't do
|
|
178
|
+
// this in the general case because it breaks assumptions with the
|
|
179
|
+
// NotImplemented symbol exported by typeshed's builtins.pyi. Instead,
|
|
180
|
+
// we'll special-case only None.
|
|
181
|
+
if ((0, types_1.isUnknown)(ancestorType)) {
|
|
182
|
+
return !(0, typeUtils_1.isNoneTypeClass)(destType);
|
|
183
|
+
}
|
|
184
|
+
// If this isn't the first time through the loop, specialize
|
|
185
|
+
// for the next ancestor in the chain.
|
|
186
|
+
if (ancestorIndex < inheritanceChain.length - 1) {
|
|
187
|
+
// If the curSrcType is a NamedTuple and the ancestorType is a tuple,
|
|
188
|
+
// we need to handle this as a special case because the NamedTuple may
|
|
189
|
+
// include typeParams from its parent class.
|
|
190
|
+
let effectiveCurSrcType = curSrcType;
|
|
191
|
+
if (types_1.ClassType.isBuiltIn(curSrcType, 'NamedTuple') &&
|
|
192
|
+
types_1.ClassType.isBuiltIn(ancestorType, 'tuple') &&
|
|
193
|
+
prevSrcType) {
|
|
194
|
+
effectiveCurSrcType = prevSrcType;
|
|
195
|
+
}
|
|
196
|
+
curSrcType = (0, typeUtils_1.specializeForBaseClass)(effectiveCurSrcType, ancestorType);
|
|
197
|
+
}
|
|
198
|
+
// If there are no type parameters on this class, we're done.
|
|
199
|
+
const ancestorTypeParams = types_1.ClassType.getTypeParams(ancestorType);
|
|
200
|
+
if (ancestorTypeParams.length === 0) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
// If the dest type isn't specialized, there are no type args to validate.
|
|
204
|
+
if (!ancestorType.priv.typeArgs) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
prevSrcType = curSrcType;
|
|
208
|
+
}
|
|
209
|
+
// Handle tuple, which supports a variable number of type arguments.
|
|
210
|
+
if (destType.priv.tupleTypeArgs && curSrcType.priv.tupleTypeArgs) {
|
|
211
|
+
return (0, tuples_1.assignTupleTypeArgs)(evaluatorInterface, destType, curSrcType, diag, constraints, flags, recursionCount);
|
|
212
|
+
}
|
|
213
|
+
if (destType.priv.typeArgs) {
|
|
214
|
+
// If the dest type is specialized, make sure the specialized source
|
|
215
|
+
// type arguments are assignable to the dest type arguments.
|
|
216
|
+
return assignTypeArgs(destType, curSrcType,
|
|
217
|
+
// Don't emit a diag addendum if we're in an invariant context. It's
|
|
218
|
+
// sufficient to simply indicate that the types are not the same
|
|
219
|
+
// in this case. Adding more information is unnecessary and confusing.
|
|
220
|
+
(flags & 1 /* AssignTypeFlags.Invariant */) === 0 ? diag : undefined, constraints, flags, recursionCount);
|
|
221
|
+
}
|
|
222
|
+
if (constraints && curSrcType.priv.typeArgs) {
|
|
223
|
+
// Populate the typeVar map with type arguments of the source.
|
|
224
|
+
const srcTypeArgs = curSrcType.priv.typeArgs;
|
|
225
|
+
for (let i = 0; i < destType.shared.typeParams.length; i++) {
|
|
226
|
+
let typeArgType;
|
|
227
|
+
const typeParam = destType.shared.typeParams[i];
|
|
228
|
+
const variance = types_1.TypeVarType.getVariance(typeParam);
|
|
229
|
+
if (curSrcType.priv.tupleTypeArgs) {
|
|
230
|
+
typeArgType = (0, typeUtils_1.convertToInstance)((0, tuples_1.makeTupleObject)(evaluatorInterface, curSrcType.priv.tupleTypeArgs, /* isUnpacked */ true));
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
typeArgType = i < srcTypeArgs.length ? srcTypeArgs[i] : types_1.UnknownType.create();
|
|
234
|
+
}
|
|
235
|
+
constraints.setBounds(typeParam, variance !== 4 /* Variance.Contravariant */ ? typeArgType : undefined, variance !== 3 /* Variance.Covariant */ ? typeArgType : undefined,
|
|
236
|
+
/* retainLiterals */ true);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
function assignRecursiveTypeAliasToSelf(destAliasInfo, srcAliasInfo, diag, constraints, flags = 0 /* AssignTypeFlags.Default */, recursionCount = 0) {
|
|
242
|
+
(0, debug_1.assert)(destAliasInfo.typeArgs !== undefined);
|
|
243
|
+
(0, debug_1.assert)(srcAliasInfo.typeArgs !== undefined);
|
|
244
|
+
let isAssignable = true;
|
|
245
|
+
const srcTypeArgs = srcAliasInfo.typeArgs;
|
|
246
|
+
const variances = destAliasInfo.shared.computedVariance;
|
|
247
|
+
destAliasInfo.typeArgs.forEach((destTypeArg, index) => {
|
|
248
|
+
const srcTypeArg = index < srcTypeArgs.length ? srcTypeArgs[index] : types_1.UnknownType.create();
|
|
249
|
+
let adjFlags = flags;
|
|
250
|
+
const variance = variances && index < variances.length ? variances[index] : 3 /* Variance.Covariant */;
|
|
251
|
+
if (variance === 2 /* Variance.Invariant */) {
|
|
252
|
+
adjFlags |= 1 /* AssignTypeFlags.Invariant */;
|
|
253
|
+
}
|
|
254
|
+
else if (variance === 4 /* Variance.Contravariant */) {
|
|
255
|
+
adjFlags ^= 2 /* AssignTypeFlags.Contravariant */;
|
|
256
|
+
}
|
|
257
|
+
if (!assignType(destTypeArg, srcTypeArg, diag, constraints, adjFlags, recursionCount)) {
|
|
258
|
+
isAssignable = false;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
return isAssignable;
|
|
262
|
+
}
|
|
263
|
+
function assignFromUnionType(destType, srcType, diag, constraints, flags, recursionCount) {
|
|
264
|
+
// Start by checking for an exact match. This is needed to handle unions
|
|
265
|
+
// that contain recursive type aliases.
|
|
266
|
+
if ((0, types_1.isTypeSame)(srcType, destType, {}, recursionCount)) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
if ((flags & 16 /* AssignTypeFlags.OverloadOverlap */) !== 0 &&
|
|
270
|
+
srcType.priv.subtypes.some((subtype) => (0, types_1.isAnyOrUnknown)(subtype))) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
// Sort the subtypes so we have a deterministic order for unions.
|
|
274
|
+
let sortedSrcTypes = (0, typeUtils_1.sortTypes)(srcType.priv.subtypes);
|
|
275
|
+
let matchedSomeSubtypes = false;
|
|
276
|
+
// Handle the case where the source and dest are both unions. Try
|
|
277
|
+
// to eliminate as many exact type matches between the src and dest.
|
|
278
|
+
if ((0, types_1.isUnion)(destType)) {
|
|
279
|
+
// Handle the special case where the dest is a union of Any and
|
|
280
|
+
// a type variable. This occurs, for example, with the return type of
|
|
281
|
+
// the getattr function.
|
|
282
|
+
const nonAnySubtypes = destType.priv.subtypes.filter((t) => !(0, types_1.isAnyOrUnknown)(t));
|
|
283
|
+
if (nonAnySubtypes.length === 1 && (0, types_1.isTypeVar)(nonAnySubtypes[0])) {
|
|
284
|
+
assignType(nonAnySubtypes[0], srcType, /* diag */ undefined, constraints, flags, recursionCount);
|
|
285
|
+
// This always succeeds because the destination contains Any.
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
const remainingDestSubtypes = [];
|
|
289
|
+
let remainingSrcSubtypes = sortedSrcTypes;
|
|
290
|
+
let canUseFastPath = true;
|
|
291
|
+
// First attempt to match all of the non-generic types in the dest
|
|
292
|
+
// to non-generic types in the source.
|
|
293
|
+
(0, typeUtils_1.sortTypes)(destType.priv.subtypes).forEach((destSubtype) => {
|
|
294
|
+
if ((0, typeUtils_1.requiresSpecialization)(destSubtype)) {
|
|
295
|
+
remainingDestSubtypes.push(destSubtype);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
const srcTypeIndex = remainingSrcSubtypes.findIndex((srcSubtype) => (0, types_1.isTypeSame)(srcSubtype, destSubtype, {}, recursionCount));
|
|
299
|
+
if (srcTypeIndex >= 0) {
|
|
300
|
+
remainingSrcSubtypes.splice(srcTypeIndex, 1);
|
|
301
|
+
matchedSomeSubtypes = true;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
remainingDestSubtypes.push(destSubtype);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
// For all remaining source subtypes, attempt to find a dest subtype
|
|
309
|
+
// whose primary type matches.
|
|
310
|
+
remainingSrcSubtypes.forEach((srcSubtype) => {
|
|
311
|
+
const destTypeIndex = remainingDestSubtypes.findIndex((destSubtype) => {
|
|
312
|
+
if ((0, types_1.isTypeSame)(destSubtype, srcSubtype)) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
if ((0, types_1.isClass)(srcSubtype) &&
|
|
316
|
+
(0, types_1.isClass)(destSubtype) &&
|
|
317
|
+
types_1.TypeBase.isInstance(srcSubtype) === types_1.TypeBase.isInstance(destSubtype)) {
|
|
318
|
+
if (types_1.ClassType.isSameGenericClass(srcSubtype, destSubtype)) {
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
// Are they equivalent TypedDicts?
|
|
322
|
+
if (types_1.ClassType.isTypedDictClass(srcSubtype) && types_1.ClassType.isTypedDictClass(destSubtype)) {
|
|
323
|
+
if (assignType(srcSubtype, destSubtype,
|
|
324
|
+
/* diag */ undefined,
|
|
325
|
+
/* constraints */ undefined, flags, recursionCount)) {
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if ((0, types_1.isFunctionOrOverloaded)(srcSubtype) && (0, types_1.isFunctionOrOverloaded)(destSubtype)) {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
});
|
|
335
|
+
if (destTypeIndex >= 0) {
|
|
336
|
+
if (assignType(remainingDestSubtypes[destTypeIndex], srcSubtype,
|
|
337
|
+
/* diag */ undefined, constraints, flags, recursionCount)) {
|
|
338
|
+
// Note that we have matched at least one subtype indicating
|
|
339
|
+
// there is at least some overlap.
|
|
340
|
+
matchedSomeSubtypes = true;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
canUseFastPath = false;
|
|
344
|
+
}
|
|
345
|
+
remainingDestSubtypes.splice(destTypeIndex, 1);
|
|
346
|
+
remainingSrcSubtypes = remainingSrcSubtypes.filter((t) => t !== srcSubtype);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
// If there is are remaining dest subtypes and they're all type variables,
|
|
350
|
+
// attempt to assign the remaining source subtypes to them.
|
|
351
|
+
if (canUseFastPath && (remainingDestSubtypes.length !== 0 || remainingSrcSubtypes.length !== 0)) {
|
|
352
|
+
if ((flags & 1 /* AssignTypeFlags.Invariant */) !== 0) {
|
|
353
|
+
// If we have no src subtypes remaining but not all dest types have been subsumed
|
|
354
|
+
// by other dest types, then the types are not compatible if we're enforcing invariance.
|
|
355
|
+
if (remainingSrcSubtypes.length === 0) {
|
|
356
|
+
return remainingDestSubtypes.every((destSubtype) => isTypeSubsumedByOtherType(destSubtype, destType,
|
|
357
|
+
/* allowAnyToSubsume */ true, recursionCount));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const isContra = (flags & 2 /* AssignTypeFlags.Contravariant */) !== 0;
|
|
361
|
+
const effectiveDestSubtypes = isContra ? remainingSrcSubtypes : remainingDestSubtypes;
|
|
362
|
+
if (effectiveDestSubtypes.length === 0 || effectiveDestSubtypes.some((t) => !(0, types_1.isTypeVar)(t))) {
|
|
363
|
+
canUseFastPath = false;
|
|
364
|
+
// We can avoid checking the source subtypes that have already been checked.
|
|
365
|
+
sortedSrcTypes = remainingSrcSubtypes;
|
|
366
|
+
}
|
|
367
|
+
else if (remainingDestSubtypes.length === remainingSrcSubtypes.length) {
|
|
368
|
+
// If the number of remaining source subtypes is the same as the number
|
|
369
|
+
// of dest TypeVars, try to assign each source subtype to its own dest TypeVar.
|
|
370
|
+
const reorderedDestSubtypes = [...remainingDestSubtypes];
|
|
371
|
+
for (let srcIndex = 0; srcIndex < remainingSrcSubtypes.length; srcIndex++) {
|
|
372
|
+
let foundMatchForSrc = false;
|
|
373
|
+
for (let destIndex = 0; destIndex < reorderedDestSubtypes.length; destIndex++) {
|
|
374
|
+
if (assignType(reorderedDestSubtypes[destIndex], remainingSrcSubtypes[srcIndex], diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
375
|
+
foundMatchForSrc = true;
|
|
376
|
+
// Move the matched dest TypeVar to the end of the list so the other
|
|
377
|
+
// dest TypeVars have a better chance of being assigned to.
|
|
378
|
+
reorderedDestSubtypes.push(...reorderedDestSubtypes.splice(destIndex, 1));
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (!foundMatchForSrc) {
|
|
383
|
+
canUseFastPath = false;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// We can avoid checking the source subtypes that have already been checked.
|
|
388
|
+
sortedSrcTypes = remainingSrcSubtypes;
|
|
389
|
+
}
|
|
390
|
+
else if (remainingSrcSubtypes.length === 0) {
|
|
391
|
+
if ((flags & 2048 /* AssignTypeFlags.PopulateExpectedType */) !== 0) {
|
|
392
|
+
// If we're populating an expected type, try not to leave
|
|
393
|
+
// any TypeVars unsolved. Assign the full type to the remaining
|
|
394
|
+
// dest TypeVars.
|
|
395
|
+
remainingDestSubtypes.forEach((destSubtype) => {
|
|
396
|
+
assignType(destSubtype, srcType, /* diag */ undefined, constraints, flags, recursionCount);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
// If we've assigned all of the source subtypes but one or more dest
|
|
400
|
+
// TypeVars have gone unmatched, treat this as success.
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
// Try to assign a union of the remaining source types to
|
|
404
|
+
// the first destination TypeVar. If this is a contravariant
|
|
405
|
+
// context, use the full dest type rather than the remaining
|
|
406
|
+
// dest subtypes to keep the lower bound as wide as possible.
|
|
407
|
+
if (!assignType(isContra ? destType : remainingDestSubtypes[0], isContra ? remainingSrcSubtypes[0] : (0, types_1.combineTypes)(remainingSrcSubtypes), diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
408
|
+
canUseFastPath = false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (canUseFastPath) {
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
// If we're looking for type overlaps and at least one type was matched,
|
|
416
|
+
// consider it as assignable.
|
|
417
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) !== 0 && matchedSomeSubtypes) {
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
let isIncompatible = false;
|
|
422
|
+
sortedSrcTypes.forEach((subtype) => {
|
|
423
|
+
if (isIncompatible) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (!assignType(destType, subtype, /* diag */ undefined, constraints, flags, recursionCount)) {
|
|
427
|
+
// Determine if the current subtype is subsumed by another subtype
|
|
428
|
+
// in the same union. If so, we can ignore this.
|
|
429
|
+
const isSubtypeSubsumed = isTypeSubsumedByOtherType(subtype, srcType,
|
|
430
|
+
/* allowAnyToSubsume */ false, recursionCount);
|
|
431
|
+
// Try again with a concrete version of the subtype.
|
|
432
|
+
if (!isSubtypeSubsumed &&
|
|
433
|
+
!assignType(destType, subtype, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
434
|
+
isIncompatible = true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
matchedSomeSubtypes = true;
|
|
439
|
+
}
|
|
440
|
+
}, /* sortSubtypes */ true);
|
|
441
|
+
if (isIncompatible) {
|
|
442
|
+
// If we're looking for type overlaps and at least one type was matched,
|
|
443
|
+
// consider it as assignable.
|
|
444
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) !== 0 && matchedSomeSubtypes) {
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
diag?.addMessage(localize_1.LocAddendum.typeAssignmentMismatch().format(printSrcDestTypes(srcType, destType)));
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
function assignToUnionType(destType, srcType, diag, constraints, flags, recursionCount) {
|
|
453
|
+
// If we need to enforce invariance, the source needs to be compatible
|
|
454
|
+
// with all subtypes in the dest, unless those subtypes are subclasses
|
|
455
|
+
// of other subtypes.
|
|
456
|
+
if (flags & 1 /* AssignTypeFlags.Invariant */) {
|
|
457
|
+
let isIncompatible = false;
|
|
458
|
+
(0, typeUtils_1.doForEachSubtype)(destType, (subtype, index) => {
|
|
459
|
+
if (!isIncompatible &&
|
|
460
|
+
!assignType(subtype, srcType, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
461
|
+
// Determine whether this subtype is subsumed by some other
|
|
462
|
+
// subtype in the union. If so, we can ignore the incompatibility.
|
|
463
|
+
let skipSubtype = false;
|
|
464
|
+
if (!(0, types_1.isAnyOrUnknown)(subtype)) {
|
|
465
|
+
const adjSubtype = (0, typeUtils_1.makeTypeVarsBound)(subtype, /* scopeIds */ undefined);
|
|
466
|
+
(0, typeUtils_1.doForEachSubtype)(destType, (otherSubtype, otherIndex) => {
|
|
467
|
+
if (index !== otherIndex && !skipSubtype) {
|
|
468
|
+
const adjOtherSubtype = (0, typeUtils_1.makeTypeVarsBound)(otherSubtype, /* scopeIds */ undefined);
|
|
469
|
+
if (assignType(adjOtherSubtype, adjSubtype,
|
|
470
|
+
/* diag */ undefined,
|
|
471
|
+
/* constraints */ undefined, 0 /* AssignTypeFlags.Default */, recursionCount)) {
|
|
472
|
+
skipSubtype = true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (!skipSubtype) {
|
|
478
|
+
isIncompatible = true;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
if (isIncompatible) {
|
|
483
|
+
diag?.addMessage(localize_1.LocAddendum.typeAssignmentMismatch().format(printSrcDestTypes(srcType, destType)));
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
// For union destinations, we just need to match one of the types.
|
|
489
|
+
const diagAddendum = diag ? new diagnostic_1.DiagnosticAddendum() : undefined;
|
|
490
|
+
let foundMatch = false;
|
|
491
|
+
// Does the union contain any type variables that need to be solved?
|
|
492
|
+
// If so, we need to use a slower path.
|
|
493
|
+
if (!(0, typeUtils_1.requiresSpecialization)(destType)) {
|
|
494
|
+
for (const subtype of destType.priv.subtypes) {
|
|
495
|
+
if (assignType(subtype, srcType, diagAddendum?.createAddendum(), constraints, flags, recursionCount)) {
|
|
496
|
+
foundMatch = true;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
// Run through all subtypes in the union. Don't stop at the first
|
|
503
|
+
// match we find because we may need to match TypeVars in other
|
|
504
|
+
// subtypes. We special-case "None" so we can handle Optional[T]
|
|
505
|
+
// without matching the None to the type var.
|
|
506
|
+
if ((0, typeUtils_1.isNoneInstance)(srcType) && (0, typeUtils_1.isOptionalType)(destType)) {
|
|
507
|
+
foundMatch = true;
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
let bestConstraints;
|
|
511
|
+
let bestConstraintsScore;
|
|
512
|
+
let nakedTypeVarMatches = 0;
|
|
513
|
+
// If the srcType is a literal, try to use the fast-path lookup
|
|
514
|
+
// in case the destType is a union with hundreds of literals.
|
|
515
|
+
if ((0, types_1.isClassInstance)(srcType) &&
|
|
516
|
+
(0, typeUtils_1.isLiteralType)(srcType) &&
|
|
517
|
+
types_1.UnionType.containsType(destType, srcType,
|
|
518
|
+
/* options */ undefined,
|
|
519
|
+
/* exclusionSet */ undefined, recursionCount)) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
(0, typeUtils_1.doForEachSubtype)(destType, (subtype) => {
|
|
523
|
+
// Make a temporary clone of the constraints. We don't want to modify
|
|
524
|
+
// the original constraints until we find the "optimal" typeVar mapping.
|
|
525
|
+
const constraintsClone = constraints?.clone();
|
|
526
|
+
if (assignType(subtype, srcType, diagAddendum?.createAddendum(), constraintsClone, flags, recursionCount)) {
|
|
527
|
+
foundMatch = true;
|
|
528
|
+
if (constraintsClone) {
|
|
529
|
+
// Ask the constraints to compute a "score" for the current
|
|
530
|
+
// contents of the table.
|
|
531
|
+
let constraintsScore = constraintsClone.getScore();
|
|
532
|
+
if ((0, types_1.isTypeVar)(subtype)) {
|
|
533
|
+
if (!constraints?.getMainConstraintSet().getTypeVar(subtype)) {
|
|
534
|
+
nakedTypeVarMatches++;
|
|
535
|
+
// Handicap the solution slightly so another type var with
|
|
536
|
+
// existing constraints will be preferred.
|
|
537
|
+
constraintsScore += 0.001;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
// If the type matches exactly, prefer it over other types.
|
|
541
|
+
if ((0, types_1.isTypeSame)(subtype, stripLiteralValue(srcType))) {
|
|
542
|
+
constraintsScore = Number.POSITIVE_INFINITY;
|
|
543
|
+
}
|
|
544
|
+
if (bestConstraintsScore === undefined || bestConstraintsScore <= constraintsScore) {
|
|
545
|
+
// We found a typeVar mapping with a higher score than before.
|
|
546
|
+
bestConstraintsScore = constraintsScore;
|
|
547
|
+
bestConstraints = constraintsClone;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
/* sortSubtypes */ true);
|
|
553
|
+
// If we saw more than one "naked" type vars that have no
|
|
554
|
+
// previous constraints recorded, it's dangerous for us to
|
|
555
|
+
// assign a value to any of these type vars at this time.
|
|
556
|
+
// Typically, they will receive some constraints via some
|
|
557
|
+
// later argument assignment.
|
|
558
|
+
if (nakedTypeVarMatches > 1 && (flags & 8 /* AssignTypeFlags.ArgAssignmentFirstPass */) !== 0) {
|
|
559
|
+
bestConstraints = undefined;
|
|
560
|
+
}
|
|
561
|
+
// If we found a winning type var mapping, copy it back to constraints.
|
|
562
|
+
if (constraints && bestConstraints) {
|
|
563
|
+
constraints.copyFromClone(bestConstraints);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
// If the source is a constrained TypeVar, see if we can assign all of the
|
|
568
|
+
// constraints to the union.
|
|
569
|
+
if (!foundMatch) {
|
|
570
|
+
if ((0, types_1.isTypeVar)(srcType) && types_1.TypeVarType.hasConstraints(srcType)) {
|
|
571
|
+
foundMatch = assignType(destType, makeTopLevelTypeVarsConcrete(srcType), diagAddendum?.createAddendum(), constraints, flags, recursionCount);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (!foundMatch) {
|
|
575
|
+
if (diag && diagAddendum) {
|
|
576
|
+
diag.addMessage(localize_1.LocAddendum.typeAssignmentMismatch().format(printSrcDestTypes(srcType, destType)));
|
|
577
|
+
diag.addAddendum(diagAddendum);
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
function assignConditionalTypeToTypeVar(destType, srcType, recursionCount) {
|
|
584
|
+
// The srcType is assignable only if all of its subtypes are assignable.
|
|
585
|
+
return !(0, types_1.findSubtype)(srcType, (srcSubtype) => {
|
|
586
|
+
if ((0, types_1.isTypeSame)(destType, srcSubtype, { ignorePseudoGeneric: true }, recursionCount)) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
if ((0, typeUtils_1.isIncompleteUnknown)(srcSubtype)) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
const destTypeVarName = types_1.TypeVarType.getNameWithScope(destType);
|
|
593
|
+
// Determine which conditions on this type apply to this type variable.
|
|
594
|
+
// There might be more than one of them.
|
|
595
|
+
const applicableConditions = ((0, typeUtils_1.getTypeCondition)(srcSubtype) ?? []).filter((constraint) => constraint.typeVar.priv.nameWithScope === destTypeVarName);
|
|
596
|
+
// If there are no applicable conditions, it's not assignable.
|
|
597
|
+
if (applicableConditions.length === 0) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
return !applicableConditions.some((condition) => {
|
|
601
|
+
if (condition.typeVar.priv.nameWithScope === types_1.TypeVarType.getNameWithScope(destType)) {
|
|
602
|
+
if (destType.shared.boundType) {
|
|
603
|
+
(0, debug_1.assert)(condition.constraintIndex === 0, 'Expected constraint for bound TypeVar to have index of 0');
|
|
604
|
+
return assignType(destType.shared.boundType, srcSubtype,
|
|
605
|
+
/* diag */ undefined,
|
|
606
|
+
/* constraints */ undefined, 0 /* AssignTypeFlags.Default */, recursionCount);
|
|
607
|
+
}
|
|
608
|
+
if (types_1.TypeVarType.hasConstraints(destType)) {
|
|
609
|
+
(0, debug_1.assert)(condition.constraintIndex < destType.shared.constraints.length, 'Constraint for constrained TypeVar is out of bounds');
|
|
610
|
+
return assignType(destType.shared.constraints[condition.constraintIndex], srcSubtype,
|
|
611
|
+
/* diag */ undefined,
|
|
612
|
+
/* constraints */ undefined, 0 /* AssignTypeFlags.Default */, recursionCount);
|
|
613
|
+
}
|
|
614
|
+
// This is a non-bound and non-constrained type variable with a matching condition.
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
617
|
+
return false;
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function assignParam(destType, srcType, paramIndex, diag, constraints, flags, recursionCount) {
|
|
622
|
+
if ((0, types_1.isTypeVarTuple)(destType) && !(0, types_1.isUnpacked)(srcType)) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
let specializedSrcType = srcType;
|
|
626
|
+
let specializedDestType = destType;
|
|
627
|
+
let doSpecializationStep = false;
|
|
628
|
+
if ((flags & 16 /* AssignTypeFlags.OverloadOverlap */) === 0) {
|
|
629
|
+
const isFirstPass = (flags & 8 /* AssignTypeFlags.ArgAssignmentFirstPass */) !== 0;
|
|
630
|
+
if ((flags & 2 /* AssignTypeFlags.Contravariant */) === 0) {
|
|
631
|
+
if (!isFirstPass) {
|
|
632
|
+
specializedDestType = solveAndApplyConstraints(destType, constraints,
|
|
633
|
+
/* applyOptions */ undefined, { useLowerBoundOnly: true });
|
|
634
|
+
}
|
|
635
|
+
doSpecializationStep = (0, typeUtils_1.requiresSpecialization)(specializedDestType);
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
if (!isFirstPass) {
|
|
639
|
+
specializedSrcType = solveAndApplyConstraints(srcType, constraints, /* applyOptions */ undefined, {
|
|
640
|
+
useLowerBoundOnly: true,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
doSpecializationStep = (0, typeUtils_1.requiresSpecialization)(specializedSrcType);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
// Is an additional specialization step required?
|
|
647
|
+
if (doSpecializationStep) {
|
|
648
|
+
if (assignType(specializedSrcType, specializedDestType,
|
|
649
|
+
/* diag */ undefined, constraints, (flags ^ 2 /* AssignTypeFlags.Contravariant */) | 256 /* AssignTypeFlags.RetainLiteralsForTypeVar */, recursionCount)) {
|
|
650
|
+
specializedDestType = solveAndApplyConstraints(destType, constraints);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (!assignType(specializedSrcType, specializedDestType, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
654
|
+
if (diag && paramIndex !== undefined) {
|
|
655
|
+
diag.addMessage(localize_1.LocAddendum.paramAssignment().format({
|
|
656
|
+
index: paramIndex + 1,
|
|
657
|
+
sourceType: printType(destType),
|
|
658
|
+
destType: printType(srcType),
|
|
659
|
+
}));
|
|
660
|
+
}
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
function assignFunction(destType, srcType, diag, constraints, flags, recursionCount) {
|
|
666
|
+
let canAssign = true;
|
|
667
|
+
const checkReturnType = (flags & 64 /* AssignTypeFlags.SkipReturnTypeCheck */) === 0;
|
|
668
|
+
const isContra = (flags & 2 /* AssignTypeFlags.Contravariant */) !== 0;
|
|
669
|
+
flags &= ~64 /* AssignTypeFlags.SkipReturnTypeCheck */;
|
|
670
|
+
const destParamSpec = types_1.FunctionType.getParamSpecFromArgsKwargs(destType);
|
|
671
|
+
if (destParamSpec) {
|
|
672
|
+
destType = types_1.FunctionType.cloneRemoveParamSpecArgsKwargs(destType);
|
|
673
|
+
}
|
|
674
|
+
const srcParamSpec = types_1.FunctionType.getParamSpecFromArgsKwargs(srcType);
|
|
675
|
+
if (srcParamSpec) {
|
|
676
|
+
srcType = types_1.FunctionType.cloneRemoveParamSpecArgsKwargs(srcType);
|
|
677
|
+
}
|
|
678
|
+
const destParamDetails = (0, parameterUtils_1.getParamListDetails)(destType, {
|
|
679
|
+
disallowExtraKwargsForTd: (flags & 131072 /* AssignTypeFlags.DisallowExtraKwargsForTd */) !== 0,
|
|
680
|
+
});
|
|
681
|
+
const srcParamDetails = (0, parameterUtils_1.getParamListDetails)(srcType, {
|
|
682
|
+
disallowExtraKwargsForTd: (flags & 131072 /* AssignTypeFlags.DisallowExtraKwargsForTd */) !== 0,
|
|
683
|
+
});
|
|
684
|
+
adjustSourceParamDetailsForDestVariadic(isContra ? destParamDetails : srcParamDetails, isContra ? srcParamDetails : destParamDetails);
|
|
685
|
+
let paramListOmissionResult;
|
|
686
|
+
const checkParamListOmission = () => {
|
|
687
|
+
if (paramListOmissionResult === undefined) {
|
|
688
|
+
paramListOmissionResult = isParamListOverlapOnlyByOmission(destType, srcType, destParamDetails, srcParamDetails, recursionCount);
|
|
689
|
+
}
|
|
690
|
+
return paramListOmissionResult;
|
|
691
|
+
};
|
|
692
|
+
const targetIncludesParamSpec = isContra ? !!srcParamSpec : !!destParamSpec;
|
|
693
|
+
const destPositionalCount = destParamDetails.firstKeywordOnlyIndex ?? destParamDetails.params.length;
|
|
694
|
+
const srcPositionalCount = srcParamDetails.firstKeywordOnlyIndex ?? srcParamDetails.params.length;
|
|
695
|
+
const positionalsToMatch = Math.min(destPositionalCount, srcPositionalCount);
|
|
696
|
+
const skippedPosParamIndices = [];
|
|
697
|
+
// Match positional parameters.
|
|
698
|
+
for (let paramIndex = 0; paramIndex < positionalsToMatch; paramIndex++) {
|
|
699
|
+
if (paramIndex === 0 &&
|
|
700
|
+
destType.shared.methodClass &&
|
|
701
|
+
(flags & 32768 /* AssignTypeFlags.SkipSelfClsParamCheck */) !== 0) {
|
|
702
|
+
if (types_1.FunctionType.isInstanceMethod(destType) || types_1.FunctionType.isClassMethod(destType)) {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
// Skip over the *args parameter since it's handled separately below.
|
|
707
|
+
if (paramIndex === destParamDetails.argsIndex) {
|
|
708
|
+
if (!(0, types_1.isUnpackedTypeVarTuple)(destParamDetails.params[destParamDetails.argsIndex].type)) {
|
|
709
|
+
skippedPosParamIndices.push(paramIndex);
|
|
710
|
+
}
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const destParam = destParamDetails.params[paramIndex];
|
|
714
|
+
const srcParam = srcParamDetails.params[paramIndex];
|
|
715
|
+
// Find the original index of this source param. If we synthesized it above (for
|
|
716
|
+
// a variadic parameter), it may not be found.
|
|
717
|
+
const srcParamType = srcParam.type;
|
|
718
|
+
const destParamType = destParam.type;
|
|
719
|
+
const destParamName = destParam.param.name ?? '';
|
|
720
|
+
const srcParamName = srcParam.param.name ?? '';
|
|
721
|
+
if (destParamName) {
|
|
722
|
+
const isDestPositionalOnly = destParam.kind === parameterUtils_1.ParamKind.Positional || destParam.kind === parameterUtils_1.ParamKind.ExpandedArgs;
|
|
723
|
+
if (!isDestPositionalOnly &&
|
|
724
|
+
destParam.param.category !== 1 /* ParamCategory.ArgsList */ &&
|
|
725
|
+
srcParam.param.category !== 1 /* ParamCategory.ArgsList */) {
|
|
726
|
+
if (srcParam.kind === parameterUtils_1.ParamKind.Positional || srcParam.kind === parameterUtils_1.ParamKind.ExpandedArgs) {
|
|
727
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.functionParamPositionOnly().format({
|
|
728
|
+
name: destParamName,
|
|
729
|
+
}));
|
|
730
|
+
canAssign = false;
|
|
731
|
+
}
|
|
732
|
+
else if (destParamName !== srcParamName) {
|
|
733
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.functionParamName().format({
|
|
734
|
+
srcName: srcParamName,
|
|
735
|
+
destName: destParamName,
|
|
736
|
+
}));
|
|
737
|
+
canAssign = false;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (destParam.defaultType) {
|
|
742
|
+
if (!srcParam.defaultType && paramIndex !== srcParamDetails.argsIndex) {
|
|
743
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.functionParamDefaultMissing().format({
|
|
744
|
+
name: srcParamName,
|
|
745
|
+
}));
|
|
746
|
+
canAssign = false;
|
|
747
|
+
}
|
|
748
|
+
// If we're performing a partial overload match and both the source
|
|
749
|
+
// and dest parameters provide defaults, assume that there could
|
|
750
|
+
// be a match.
|
|
751
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) !== 0) {
|
|
752
|
+
if (srcParam.defaultType) {
|
|
753
|
+
if ((0, typeUtils_1.isOverlapOnlyByOmission)(destParamType, destParam.defaultType, srcParamType) &&
|
|
754
|
+
checkParamListOmission()) {
|
|
755
|
+
canAssign = false;
|
|
756
|
+
}
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// Handle the special case of an overloaded __init__ method whose self
|
|
762
|
+
// parameter is annotated.
|
|
763
|
+
if (paramIndex === 0 &&
|
|
764
|
+
srcType.shared.name === '__init__' &&
|
|
765
|
+
types_1.FunctionType.isInstanceMethod(srcType) &&
|
|
766
|
+
destType.shared.name === '__init__' &&
|
|
767
|
+
types_1.FunctionType.isInstanceMethod(destType) &&
|
|
768
|
+
types_1.FunctionType.isOverloaded(destType) &&
|
|
769
|
+
types_1.FunctionParam.isTypeDeclared(destParam.param)) {
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if ((0, types_1.isUnpacked)(srcParamType)) {
|
|
773
|
+
canAssign = false;
|
|
774
|
+
}
|
|
775
|
+
else if (!assignParam(destParamType, srcParamType, paramIndex, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
776
|
+
// Handle the special case where the source parameter is a synthesized
|
|
777
|
+
// TypeVar for "self" or "cls".
|
|
778
|
+
if ((flags & 512 /* AssignTypeFlags.SkipSelfClsTypeCheck */) === 0 ||
|
|
779
|
+
!(0, types_1.isTypeVar)(srcParamType) ||
|
|
780
|
+
!srcParamType.shared.isSynthesized) {
|
|
781
|
+
canAssign = false;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
else if (destParam.kind !== parameterUtils_1.ParamKind.Positional &&
|
|
785
|
+
destParam.kind !== parameterUtils_1.ParamKind.ExpandedArgs &&
|
|
786
|
+
srcParam.kind === parameterUtils_1.ParamKind.Positional &&
|
|
787
|
+
!srcParamDetails.params.some((p) => p.kind === parameterUtils_1.ParamKind.Keyword &&
|
|
788
|
+
p.param.category === 0 /* ParamCategory.Simple */ &&
|
|
789
|
+
p.param.name === destParam.param.name)) {
|
|
790
|
+
if (!assignNamedParam(destParamDetails, srcParamDetails, paramIndex, diag, constraints, flags, recursionCount)) {
|
|
791
|
+
canAssign = false;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
if (!types_1.FunctionType.isGradualCallableForm(destType) &&
|
|
796
|
+
destParamDetails.firstPositionOrKeywordIndex < srcParamDetails.positionOnlyParamCount &&
|
|
797
|
+
!targetIncludesParamSpec) {
|
|
798
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.argsPositionOnly().format({
|
|
799
|
+
expected: destParamDetails.firstPositionOrKeywordIndex,
|
|
800
|
+
received: srcParamDetails.positionOnlyParamCount,
|
|
801
|
+
}));
|
|
802
|
+
canAssign = false;
|
|
803
|
+
}
|
|
804
|
+
if (destPositionalCount < srcPositionalCount && !targetIncludesParamSpec) {
|
|
805
|
+
// Add any remaining positional parameter indices to the list that
|
|
806
|
+
// need to be validated.
|
|
807
|
+
for (let i = destPositionalCount; i < srcPositionalCount; i++) {
|
|
808
|
+
skippedPosParamIndices.push(i);
|
|
809
|
+
}
|
|
810
|
+
for (const i of skippedPosParamIndices) {
|
|
811
|
+
// If the dest has an *args parameter, make sure it can accept the remaining
|
|
812
|
+
// positional arguments in the source.
|
|
813
|
+
if (destParamDetails.argsIndex !== undefined) {
|
|
814
|
+
const destArgsType = destParamDetails.params[destParamDetails.argsIndex].type;
|
|
815
|
+
const srcParamType = srcParamDetails.params[i].type;
|
|
816
|
+
if (!assignParam(destArgsType, srcParamType, i, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
817
|
+
canAssign = false;
|
|
818
|
+
}
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
// If The source parameter has a default value, it is OK for the
|
|
822
|
+
// corresponding dest parameter to be missing.
|
|
823
|
+
const srcParam = srcParamDetails.params[i];
|
|
824
|
+
if (srcParam.defaultType) {
|
|
825
|
+
// Assign default arg value in case it is needed for
|
|
826
|
+
// populating TypeVar constraints.
|
|
827
|
+
const paramInfo = srcParamDetails.params[i];
|
|
828
|
+
const defaultArgType = paramInfo.defaultType ?? paramInfo.defaultType;
|
|
829
|
+
// Enforce invariance below because the default arg value
|
|
830
|
+
// is constructed prior to the call, so its type is already
|
|
831
|
+
// fixed.
|
|
832
|
+
if (defaultArgType &&
|
|
833
|
+
!assignType(paramInfo.type, defaultArgType, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
834
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) === 0) {
|
|
835
|
+
canAssign = false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
// If the source parameter is also addressable by keyword, it is OK
|
|
841
|
+
// that there is no matching positional parameter in the dest.
|
|
842
|
+
if (srcParam.kind === parameterUtils_1.ParamKind.Standard) {
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
// If the source parameter is a variadic, it is OK that there is no
|
|
846
|
+
// matching positional parameter in the dest.
|
|
847
|
+
if (srcParam.param.category === 1 /* ParamCategory.ArgsList */) {
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
const nonDefaultSrcParamCount = srcParamDetails.params.filter((p) => !!p.param.name && !p.defaultType && p.param.category === 0 /* ParamCategory.Simple */).length;
|
|
851
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.functionTooManyParams().format({
|
|
852
|
+
expected: destPositionalCount,
|
|
853
|
+
received: nonDefaultSrcParamCount,
|
|
854
|
+
}));
|
|
855
|
+
canAssign = false;
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
else if (srcPositionalCount < destPositionalCount) {
|
|
860
|
+
if (srcParamDetails.argsIndex !== undefined) {
|
|
861
|
+
// Make sure the remaining dest parameters can be assigned to the source
|
|
862
|
+
// *args parameter type.
|
|
863
|
+
const srcArgsType = srcParamDetails.params[srcParamDetails.argsIndex].type;
|
|
864
|
+
for (let paramIndex = srcPositionalCount; paramIndex < destPositionalCount; paramIndex++) {
|
|
865
|
+
if (paramIndex === srcParamDetails.argsIndex) {
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
const destParamType = destParamDetails.params[paramIndex].type;
|
|
869
|
+
if ((0, types_1.isTypeVarTuple)(destParamType) && !(0, types_1.isTypeVarTuple)(srcArgsType)) {
|
|
870
|
+
diag?.addMessage(localize_1.LocAddendum.typeVarTupleRequiresKnownLength());
|
|
871
|
+
canAssign = false;
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
if (!assignParam(destParamType, srcArgsType, paramIndex, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
875
|
+
canAssign = false;
|
|
876
|
+
}
|
|
877
|
+
const destParamKind = destParamDetails.params[paramIndex].kind;
|
|
878
|
+
if (destParamKind !== parameterUtils_1.ParamKind.Positional && destParamKind !== parameterUtils_1.ParamKind.ExpandedArgs) {
|
|
879
|
+
if (!assignNamedParam(destParamDetails, srcParamDetails, paramIndex, diag, constraints, flags, recursionCount)) {
|
|
880
|
+
canAssign = false;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else if (!srcParamDetails.paramSpec) {
|
|
887
|
+
// If the dest contains a *args, remove it from the positional count
|
|
888
|
+
// because it's OK for zero source args to match it.
|
|
889
|
+
let adjDestPositionalCount = destPositionalCount;
|
|
890
|
+
if (destParamDetails.argsIndex !== undefined && destParamDetails.argsIndex < destPositionalCount) {
|
|
891
|
+
adjDestPositionalCount--;
|
|
892
|
+
}
|
|
893
|
+
// If we're doing a partial overload overlap check, ignore dest positional
|
|
894
|
+
// params with default values.
|
|
895
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) !== 0) {
|
|
896
|
+
while (adjDestPositionalCount > 0 &&
|
|
897
|
+
destParamDetails.params[adjDestPositionalCount - 1].defaultType) {
|
|
898
|
+
adjDestPositionalCount--;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (srcPositionalCount < adjDestPositionalCount) {
|
|
902
|
+
diag?.addMessage(localize_1.LocAddendum.functionTooFewParams().format({
|
|
903
|
+
expected: adjDestPositionalCount,
|
|
904
|
+
received: srcPositionalCount,
|
|
905
|
+
}));
|
|
906
|
+
canAssign = false;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
// If both src and dest have an "*args" parameter, make sure
|
|
911
|
+
// their types are compatible.
|
|
912
|
+
if (srcParamDetails.argsIndex !== undefined &&
|
|
913
|
+
destParamDetails.argsIndex !== undefined &&
|
|
914
|
+
!types_1.FunctionType.isGradualCallableForm(destType)) {
|
|
915
|
+
let destArgsType = destParamDetails.params[destParamDetails.argsIndex].type;
|
|
916
|
+
let srcArgsType = srcParamDetails.params[srcParamDetails.argsIndex].type;
|
|
917
|
+
if (!(0, types_1.isUnpacked)(destArgsType)) {
|
|
918
|
+
destArgsType = (0, tuples_1.makeTupleObject)(evaluatorInterface, [{ type: destArgsType, isUnbounded: true }],
|
|
919
|
+
/* isUnpacked */ true);
|
|
920
|
+
}
|
|
921
|
+
if (!(0, types_1.isUnpacked)(srcArgsType)) {
|
|
922
|
+
srcArgsType = (0, tuples_1.makeTupleObject)(evaluatorInterface, [{ type: srcArgsType, isUnbounded: true }],
|
|
923
|
+
/* isUnpacked */ true);
|
|
924
|
+
}
|
|
925
|
+
if (!assignParam(destArgsType, srcArgsType, destParamDetails.params[destParamDetails.argsIndex].index, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
926
|
+
canAssign = false;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
// If the dest has an "*args" but the source doesn't, report the incompatibility.
|
|
930
|
+
// The converse situation is OK.
|
|
931
|
+
if (!types_1.FunctionType.isGradualCallableForm(destType) &&
|
|
932
|
+
srcParamDetails.argsIndex === undefined &&
|
|
933
|
+
srcParamSpec === undefined &&
|
|
934
|
+
destParamDetails.argsIndex !== undefined &&
|
|
935
|
+
!destParamDetails.hasUnpackedTypeVarTuple) {
|
|
936
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.argsParamMissing().format({
|
|
937
|
+
paramName: destParamDetails.params[destParamDetails.argsIndex].param.name ?? '',
|
|
938
|
+
}));
|
|
939
|
+
canAssign = false;
|
|
940
|
+
}
|
|
941
|
+
// Handle matching of named (keyword) parameters.
|
|
942
|
+
if (!targetIncludesParamSpec) {
|
|
943
|
+
// Build a dictionary of named parameters in the dest.
|
|
944
|
+
const destParamMap = new Map();
|
|
945
|
+
if (destParamDetails.firstKeywordOnlyIndex !== undefined) {
|
|
946
|
+
destParamDetails.params.forEach((param, index) => {
|
|
947
|
+
if (index >= destParamDetails.firstKeywordOnlyIndex) {
|
|
948
|
+
if (param.param.name &&
|
|
949
|
+
param.param.category === 0 /* ParamCategory.Simple */ &&
|
|
950
|
+
param.kind !== parameterUtils_1.ParamKind.Positional &&
|
|
951
|
+
param.kind !== parameterUtils_1.ParamKind.ExpandedArgs) {
|
|
952
|
+
destParamMap.set(param.param.name, param);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
// If the dest has fewer positional arguments than the source, the remaining
|
|
958
|
+
// positional arguments in the source can be treated as named arguments.
|
|
959
|
+
let srcStartOfNamed = srcParamDetails.firstKeywordOnlyIndex !== undefined
|
|
960
|
+
? srcParamDetails.firstKeywordOnlyIndex
|
|
961
|
+
: srcParamDetails.params.length;
|
|
962
|
+
if (destPositionalCount < srcPositionalCount && destParamDetails.argsIndex === undefined) {
|
|
963
|
+
srcStartOfNamed = destPositionalCount;
|
|
964
|
+
}
|
|
965
|
+
if (srcStartOfNamed >= 0) {
|
|
966
|
+
srcParamDetails.params.forEach((srcParamInfo, index) => {
|
|
967
|
+
if (index < srcStartOfNamed) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (!srcParamInfo.param.name ||
|
|
971
|
+
srcParamInfo.param.category !== 0 /* ParamCategory.Simple */ ||
|
|
972
|
+
srcParamInfo.kind === parameterUtils_1.ParamKind.Positional) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
const destParamInfo = destParamMap.get(srcParamInfo.param.name) ??
|
|
976
|
+
destParamDetails.params.find((paramInfo) => paramInfo.param.name === srcParamInfo.param.name &&
|
|
977
|
+
paramInfo.kind === parameterUtils_1.ParamKind.Standard &&
|
|
978
|
+
paramInfo.param.category === 0 /* ParamCategory.Simple */);
|
|
979
|
+
const paramDiag = diag?.createAddendum();
|
|
980
|
+
const srcParamType = srcParamInfo.type;
|
|
981
|
+
if (!destParamInfo) {
|
|
982
|
+
if (destParamDetails.kwargsIndex === undefined && !srcParamInfo.defaultType) {
|
|
983
|
+
if (paramDiag) {
|
|
984
|
+
paramDiag.addMessage(localize_1.LocAddendum.namedParamMissingInDest().format({
|
|
985
|
+
name: srcParamInfo.param.name,
|
|
986
|
+
}));
|
|
987
|
+
}
|
|
988
|
+
canAssign = false;
|
|
989
|
+
}
|
|
990
|
+
else if (destParamDetails.kwargsIndex !== undefined) {
|
|
991
|
+
// Make sure we can assign the type to the Kwargs.
|
|
992
|
+
if (!assignParam(destParamDetails.params[destParamDetails.kwargsIndex].type, srcParamType, destParamDetails.params[destParamDetails.kwargsIndex].index, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
993
|
+
canAssign = false;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
else if (srcParamInfo.defaultType) {
|
|
997
|
+
// Assign default arg values in case they are needed for
|
|
998
|
+
// populating TypeVar constraints.
|
|
999
|
+
const defaultArgType = srcParamInfo.defaultType ?? srcParamInfo.defaultType;
|
|
1000
|
+
if (defaultArgType &&
|
|
1001
|
+
!assignType(srcParamInfo.type, defaultArgType, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
1002
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) === 0) {
|
|
1003
|
+
canAssign = false;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
// A keyword-only source parameter was matched to a positional-or-keyword
|
|
1010
|
+
// dest parameter. The dest parameter can be called positionally, but a
|
|
1011
|
+
// keyword-only source parameter with no default would be left unsatisfied.
|
|
1012
|
+
if (destParamInfo.kind === parameterUtils_1.ParamKind.Standard &&
|
|
1013
|
+
srcParamInfo.kind === parameterUtils_1.ParamKind.Keyword &&
|
|
1014
|
+
!srcParamInfo.defaultType) {
|
|
1015
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) === 0) {
|
|
1016
|
+
paramDiag?.addMessage(localize_1.LocAddendum.functionParamDefaultMissing().format({
|
|
1017
|
+
name: srcParamInfo.param.name,
|
|
1018
|
+
}));
|
|
1019
|
+
canAssign = false;
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
// If we're performing a partial overload match and both the source
|
|
1024
|
+
// and dest parameters provide defaults, assume that there could
|
|
1025
|
+
// be a match.
|
|
1026
|
+
if (srcParamInfo.defaultType && destParamInfo.defaultType) {
|
|
1027
|
+
if ((flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) !== 0) {
|
|
1028
|
+
if ((0, typeUtils_1.isOverlapOnlyByOmission)(destParamInfo.type, destParamInfo.defaultType, srcParamType) &&
|
|
1029
|
+
checkParamListOmission()) {
|
|
1030
|
+
canAssign = false;
|
|
1031
|
+
}
|
|
1032
|
+
destParamMap.delete(srcParamInfo.param.name);
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
const destParamType = destParamInfo.type;
|
|
1037
|
+
const specializedDestParamType = constraints
|
|
1038
|
+
? solveAndApplyConstraints(destParamType, constraints)
|
|
1039
|
+
: destParamType;
|
|
1040
|
+
if (!assignParam(destParamInfo.type, srcParamType,
|
|
1041
|
+
/* paramIndex */ undefined, paramDiag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
1042
|
+
if (paramDiag) {
|
|
1043
|
+
paramDiag.addMessage(localize_1.LocAddendum.namedParamTypeMismatch().format({
|
|
1044
|
+
name: srcParamInfo.param.name,
|
|
1045
|
+
sourceType: printType(specializedDestParamType),
|
|
1046
|
+
destType: printType(srcParamType),
|
|
1047
|
+
}));
|
|
1048
|
+
}
|
|
1049
|
+
if (destParamInfo.kind !== parameterUtils_1.ParamKind.Standard ||
|
|
1050
|
+
(flags & 32 /* AssignTypeFlags.PartialOverloadOverlap */) === 0) {
|
|
1051
|
+
canAssign = false;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (destParamInfo.defaultType && !srcParamInfo.defaultType) {
|
|
1055
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.functionParamDefaultMissing().format({
|
|
1056
|
+
name: srcParamInfo.param.name,
|
|
1057
|
+
}));
|
|
1058
|
+
canAssign = false;
|
|
1059
|
+
}
|
|
1060
|
+
destParamMap.delete(srcParamInfo.param.name);
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
// See if there are any unmatched named parameters.
|
|
1064
|
+
destParamMap.forEach((destParamInfo, paramName) => {
|
|
1065
|
+
if (srcParamDetails.kwargsIndex !== undefined && destParamInfo.param.name) {
|
|
1066
|
+
// Make sure the src kwargs type is compatible.
|
|
1067
|
+
if (!assignParam(destParamInfo.type, srcParamDetails.params[srcParamDetails.kwargsIndex].type, destParamInfo.index, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
1068
|
+
canAssign = false;
|
|
1069
|
+
}
|
|
1070
|
+
destParamMap.delete(paramName);
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.namedParamMissingInSource().format({ name: paramName }));
|
|
1074
|
+
canAssign = false;
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
// If both src and dest have a "**kwargs" parameter, make sure their types are compatible.
|
|
1078
|
+
if (srcParamDetails.kwargsIndex !== undefined && destParamDetails.kwargsIndex !== undefined) {
|
|
1079
|
+
if (!assignParam(destParamDetails.params[destParamDetails.kwargsIndex].type, srcParamDetails.params[srcParamDetails.kwargsIndex].type, destParamDetails.params[destParamDetails.kwargsIndex].index, diag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
1080
|
+
canAssign = false;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
// If the dest has a "**kwargs" but the source doesn't, report the incompatibility.
|
|
1084
|
+
// The converse situation is OK.
|
|
1085
|
+
if (!types_1.FunctionType.isGradualCallableForm(destType) &&
|
|
1086
|
+
srcParamDetails.kwargsIndex === undefined &&
|
|
1087
|
+
srcParamSpec === undefined &&
|
|
1088
|
+
destParamDetails.kwargsIndex !== undefined) {
|
|
1089
|
+
diag?.createAddendum().addMessage(localize_1.LocAddendum.kwargsParamMissing().format({
|
|
1090
|
+
paramName: destParamDetails.params[destParamDetails.kwargsIndex].param.name,
|
|
1091
|
+
}));
|
|
1092
|
+
canAssign = false;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
if ((flags & 16 /* AssignTypeFlags.OverloadOverlap */) !== 0) {
|
|
1096
|
+
// If we're checking for full overlapping overloads and the source is
|
|
1097
|
+
// a gradual form, the dest must also be a gradual form.
|
|
1098
|
+
if (types_1.FunctionType.isGradualCallableForm(srcType) && !types_1.FunctionType.isGradualCallableForm(destType)) {
|
|
1099
|
+
canAssign = false;
|
|
1100
|
+
}
|
|
1101
|
+
// If the src contains a ParamSpec the dest must also.
|
|
1102
|
+
if (srcParamSpec && !destParamSpec) {
|
|
1103
|
+
canAssign = false;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
// If the source and the dest are using the same ParamSpec, any additional
|
|
1107
|
+
// concatenated parameters must match.
|
|
1108
|
+
if (targetIncludesParamSpec && srcParamSpec?.priv.nameWithScope === destParamSpec?.priv.nameWithScope) {
|
|
1109
|
+
if (srcParamDetails.params.length !== destParamDetails.params.length) {
|
|
1110
|
+
canAssign = false;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
// Are we assigning to a function with a ParamSpec?
|
|
1114
|
+
if (targetIncludesParamSpec) {
|
|
1115
|
+
const effectiveSrcType = isContra ? destType : srcType;
|
|
1116
|
+
const effectiveDestType = isContra ? srcType : destType;
|
|
1117
|
+
const effectiveSrcParamSpec = isContra ? destParamSpec : srcParamSpec;
|
|
1118
|
+
const effectiveDestParamSpec = isContra ? srcParamSpec : destParamSpec;
|
|
1119
|
+
if (effectiveDestParamSpec) {
|
|
1120
|
+
const requiredMatchParamCount = effectiveDestType.shared.parameters.filter((p, i) => {
|
|
1121
|
+
if (!p.name) {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
const paramType = types_1.FunctionType.getParamType(effectiveDestType, i);
|
|
1125
|
+
if (p.category === 0 /* ParamCategory.Simple */ && (0, types_1.isParamSpec)(paramType)) {
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
return true;
|
|
1129
|
+
}).length;
|
|
1130
|
+
let matchedParamCount = 0;
|
|
1131
|
+
const remainingParams = [];
|
|
1132
|
+
// If there are parameters in the source that are not matched
|
|
1133
|
+
// to parameters in the dest, assume these are concatenated on
|
|
1134
|
+
// to the ParamSpec.
|
|
1135
|
+
effectiveSrcType.shared.parameters.forEach((p, index) => {
|
|
1136
|
+
if (matchedParamCount < requiredMatchParamCount) {
|
|
1137
|
+
if (p.name) {
|
|
1138
|
+
matchedParamCount++;
|
|
1139
|
+
}
|
|
1140
|
+
// If this is a *args parameter, assume that it provides
|
|
1141
|
+
// the remaining positional parameters, but also assume
|
|
1142
|
+
// that it is not exhausted and can provide additional
|
|
1143
|
+
// parameters.
|
|
1144
|
+
if (p.category !== 1 /* ParamCategory.ArgsList */) {
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if ((0, types_1.isPositionOnlySeparator)(p) && remainingParams.length === 0) {
|
|
1149
|
+
// Don't bother pushing a position-only separator if it
|
|
1150
|
+
// is the first remaining param.
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
remainingParams.push(types_1.FunctionParam.create(p.category, types_1.FunctionType.getParamType(effectiveSrcType, index), p.flags, p.name, types_1.FunctionType.getParamDefaultType(effectiveSrcType, index), p.defaultExpr));
|
|
1154
|
+
});
|
|
1155
|
+
// If there are remaining parameters and the source and dest do not contain
|
|
1156
|
+
// the same ParamSpec, synthesize a function for the remaining parameters.
|
|
1157
|
+
if (remainingParams.length > 0 ||
|
|
1158
|
+
!effectiveSrcParamSpec ||
|
|
1159
|
+
!(0, types_1.isTypeSame)(effectiveSrcParamSpec, effectiveDestParamSpec, { ignoreTypeFlags: true })) {
|
|
1160
|
+
const effectiveSrcPosCount = isContra ? destPositionalCount : srcPositionalCount;
|
|
1161
|
+
const effectiveDestPosCount = isContra ? srcPositionalCount : destPositionalCount;
|
|
1162
|
+
// If the src and dest both have ParamSpecs but the src has additional positional
|
|
1163
|
+
// parameters that have not been matched to dest positional parameters (probably due
|
|
1164
|
+
// to a Concatenate), don't attempt to assign the remaining parameters to the ParamSpec.
|
|
1165
|
+
if (!effectiveSrcParamSpec || effectiveSrcPosCount >= effectiveDestPosCount) {
|
|
1166
|
+
const remainingFunction = types_1.FunctionType.createInstance('', '', '', effectiveSrcType.shared.flags | 64 /* FunctionTypeFlags.SynthesizedMethod */, effectiveSrcType.shared.docString);
|
|
1167
|
+
remainingFunction.shared.deprecatedMessage = effectiveSrcType.shared.deprecatedMessage;
|
|
1168
|
+
remainingFunction.shared.typeVarScopeId = effectiveSrcType.shared.typeVarScopeId;
|
|
1169
|
+
remainingFunction.priv.constructorTypeVarScopeId =
|
|
1170
|
+
effectiveSrcType.priv.constructorTypeVarScopeId;
|
|
1171
|
+
remainingFunction.shared.methodClass = effectiveSrcType.shared.methodClass;
|
|
1172
|
+
remainingParams.forEach((param) => {
|
|
1173
|
+
types_1.FunctionType.addParam(remainingFunction, param);
|
|
1174
|
+
});
|
|
1175
|
+
if (effectiveSrcParamSpec) {
|
|
1176
|
+
types_1.FunctionType.addParamSpecVariadics(remainingFunction, (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec));
|
|
1177
|
+
}
|
|
1178
|
+
if (!assignType(effectiveDestParamSpec, remainingFunction,
|
|
1179
|
+
/* diag */ undefined, constraints, flags)) {
|
|
1180
|
+
// If we couldn't assign the function to the ParamSpec, see if we can
|
|
1181
|
+
// assign only the ParamSpec. This is possible if there were no
|
|
1182
|
+
// remaining parameters.
|
|
1183
|
+
if (remainingParams.length > 0 ||
|
|
1184
|
+
!effectiveSrcParamSpec ||
|
|
1185
|
+
!assignType((0, typeUtils_1.convertToInstance)(effectiveDestParamSpec), (0, typeUtils_1.convertToInstance)(effectiveSrcParamSpec),
|
|
1186
|
+
/* diag */ undefined, constraints, flags)) {
|
|
1187
|
+
canAssign = false;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
// Match the return parameter.
|
|
1195
|
+
if (checkReturnType) {
|
|
1196
|
+
const destReturnType = getEffectiveReturnType(destType);
|
|
1197
|
+
if (!(0, types_1.isAnyOrUnknown)(destReturnType)) {
|
|
1198
|
+
const srcReturnType = solveAndApplyConstraints(getEffectiveReturnType(srcType), constraints);
|
|
1199
|
+
const returnDiag = diag?.createAddendum();
|
|
1200
|
+
let isReturnTypeCompatible = false;
|
|
1201
|
+
let effectiveFlags = flags;
|
|
1202
|
+
// If the source has a declared return type that includes a literal
|
|
1203
|
+
// in its annotation, assume that we will want the constraint
|
|
1204
|
+
// solver to retain literals.
|
|
1205
|
+
if (srcType.shared.declaredReturnType &&
|
|
1206
|
+
(0, typeUtils_1.containsLiteralType)(srcType.shared.declaredReturnType, /* includeTypeArgs */ true)) {
|
|
1207
|
+
effectiveFlags |= 256 /* AssignTypeFlags.RetainLiteralsForTypeVar */;
|
|
1208
|
+
}
|
|
1209
|
+
if (assignType(destReturnType, srcReturnType, returnDiag?.createAddendum(), constraints, effectiveFlags, recursionCount)) {
|
|
1210
|
+
isReturnTypeCompatible = true;
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
// Handle the special case where the return type is a TypeGuard[T]
|
|
1214
|
+
// or TypeIs[T]. This should also act as a bool, since that's its
|
|
1215
|
+
// type at runtime.
|
|
1216
|
+
if ((0, types_1.isClassInstance)(srcReturnType) &&
|
|
1217
|
+
types_1.ClassType.isBuiltIn(srcReturnType, ['TypeGuard', 'TypeIs']) &&
|
|
1218
|
+
context.prefetched?.boolClass &&
|
|
1219
|
+
(0, types_1.isInstantiableClass)(context.prefetched.boolClass)) {
|
|
1220
|
+
if (assignType(destReturnType, types_1.ClassType.cloneAsInstance(context.prefetched.boolClass), returnDiag?.createAddendum(), constraints, flags, recursionCount)) {
|
|
1221
|
+
isReturnTypeCompatible = true;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (!isReturnTypeCompatible) {
|
|
1226
|
+
if (returnDiag) {
|
|
1227
|
+
returnDiag.addMessage(localize_1.LocAddendum.functionReturnTypeMismatch().format({
|
|
1228
|
+
sourceType: printType(srcReturnType),
|
|
1229
|
+
destType: printType(destReturnType),
|
|
1230
|
+
}));
|
|
1231
|
+
}
|
|
1232
|
+
canAssign = false;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return canAssign;
|
|
1237
|
+
}
|
|
1238
|
+
function adjustSourceParamDetailsForDestVariadic(srcDetails, destDetails) {
|
|
1239
|
+
// If there is no *args parameter in the dest, we have nothing to do.
|
|
1240
|
+
if (destDetails.argsIndex === undefined) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
// If the *args parameter isn't an unpacked TypeVarTuple or tuple,
|
|
1244
|
+
// we have nothing to do.
|
|
1245
|
+
if (!(0, types_1.isUnpacked)(destDetails.params[destDetails.argsIndex].type)) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
// If the source doesn't have enough positional parameters, we have nothing to do.
|
|
1249
|
+
if (srcDetails.params.length < destDetails.argsIndex) {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
let srcLastToPackIndex = srcDetails.params.findIndex((p, i) => {
|
|
1253
|
+
(0, debug_1.assert)(destDetails.argsIndex !== undefined);
|
|
1254
|
+
return i >= destDetails.argsIndex && p.kind === parameterUtils_1.ParamKind.Keyword;
|
|
1255
|
+
});
|
|
1256
|
+
if (srcLastToPackIndex < 0) {
|
|
1257
|
+
srcLastToPackIndex = srcDetails.params.length;
|
|
1258
|
+
}
|
|
1259
|
+
// If both the source and dest have an *args parameter but the dest's is
|
|
1260
|
+
// in a later position, then we can't assign the source's *args to the dest.
|
|
1261
|
+
// Don't make any adjustment in this case.
|
|
1262
|
+
if (srcDetails.argsIndex !== undefined && destDetails.argsIndex > srcDetails.argsIndex) {
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const destFirstNonPositional = destDetails.firstKeywordOnlyIndex ?? destDetails.params.length;
|
|
1266
|
+
const suffixLength = destFirstNonPositional - destDetails.argsIndex - 1;
|
|
1267
|
+
const srcPositionalsToPack = srcDetails.params.slice(destDetails.argsIndex, srcLastToPackIndex - suffixLength);
|
|
1268
|
+
const srcTupleTypes = [];
|
|
1269
|
+
srcPositionalsToPack.forEach((entry) => {
|
|
1270
|
+
if (entry.param.category === 1 /* ParamCategory.ArgsList */) {
|
|
1271
|
+
if ((0, types_1.isUnpackedTypeVarTuple)(entry.type)) {
|
|
1272
|
+
srcTupleTypes.push({ type: entry.type, isUnbounded: false });
|
|
1273
|
+
}
|
|
1274
|
+
else if ((0, types_1.isUnpackedClass)(entry.type) && entry.type.priv.tupleTypeArgs) {
|
|
1275
|
+
(0, collectionUtils_1.appendArray)(srcTupleTypes, entry.type.priv.tupleTypeArgs);
|
|
1276
|
+
}
|
|
1277
|
+
else {
|
|
1278
|
+
srcTupleTypes.push({ type: entry.type, isUnbounded: true });
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
else {
|
|
1282
|
+
srcTupleTypes.push({ type: entry.type, isUnbounded: false, isOptional: !!entry.defaultType });
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
if (srcTupleTypes.length !== 1 || !(0, types_1.isTypeVarTuple)(srcTupleTypes[0].type)) {
|
|
1286
|
+
const srcPositionalsType = (0, tuples_1.makeTupleObject)(evaluatorInterface, srcTupleTypes, /* isUnpacked */ true);
|
|
1287
|
+
// Snip out the portion of the source positionals that map to the variadic
|
|
1288
|
+
// dest parameter and replace it with a single parameter that is typed as a
|
|
1289
|
+
// tuple containing the individual types of the replaced parameters.
|
|
1290
|
+
srcDetails.params = [
|
|
1291
|
+
...srcDetails.params.slice(0, destDetails.argsIndex),
|
|
1292
|
+
{
|
|
1293
|
+
param: types_1.FunctionParam.create(1 /* ParamCategory.ArgsList */, srcPositionalsType, types_1.FunctionParamFlags.NameSynthesized | types_1.FunctionParamFlags.TypeDeclared, '_arg_combined'),
|
|
1294
|
+
type: srcPositionalsType,
|
|
1295
|
+
declaredType: srcPositionalsType,
|
|
1296
|
+
index: -1,
|
|
1297
|
+
kind: parameterUtils_1.ParamKind.Positional,
|
|
1298
|
+
},
|
|
1299
|
+
...srcDetails.params.slice(destDetails.argsIndex + srcPositionalsToPack.length, srcDetails.params.length),
|
|
1300
|
+
];
|
|
1301
|
+
const argsIndex = srcDetails.params.findIndex((param) => param.param.category === 1 /* ParamCategory.ArgsList */);
|
|
1302
|
+
srcDetails.argsIndex = argsIndex >= 0 ? argsIndex : undefined;
|
|
1303
|
+
const kwargsIndex = srcDetails.params.findIndex((param) => param.param.category === 2 /* ParamCategory.KwargsDict */);
|
|
1304
|
+
srcDetails.kwargsIndex = kwargsIndex >= 0 ? kwargsIndex : undefined;
|
|
1305
|
+
const firstKeywordOnlyIndex = srcDetails.params.findIndex((param) => param.kind === parameterUtils_1.ParamKind.Keyword);
|
|
1306
|
+
srcDetails.firstKeywordOnlyIndex = firstKeywordOnlyIndex >= 0 ? firstKeywordOnlyIndex : undefined;
|
|
1307
|
+
srcDetails.positionOnlyParamCount = Math.max(0, srcDetails.params.findIndex((p) => p.kind !== parameterUtils_1.ParamKind.Positional || p.param.category !== 0 /* ParamCategory.Simple */ || !!p.defaultType));
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
return {
|
|
1311
|
+
assignClass,
|
|
1312
|
+
assignRecursiveTypeAliasToSelf,
|
|
1313
|
+
assignFromUnionType,
|
|
1314
|
+
assignToUnionType,
|
|
1315
|
+
assignConditionalTypeToTypeVar,
|
|
1316
|
+
assignParam,
|
|
1317
|
+
assignFunction,
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
//# sourceMappingURL=typeCompatibility.js.map
|