Only check excess properties on final types from inference

This commit is contained in:
Anders Hejlsberg 2017-07-26 07:16:06 -07:00
parent 2d4938d5c0
commit bd1f8c50a4

View file

@ -15238,17 +15238,17 @@ namespace ts {
if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) { if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) {
// Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter) // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
const paramType = getTypeAtPosition(signature, i); const paramType = getTypeAtPosition(signature, i);
let argType = getEffectiveArgumentType(node, i); // If the effective argument type is undefined, there is no synthetic type for the argument.
// In that case, we should check the argument.
// If the effective argument type is 'undefined', there is no synthetic type const argType = getEffectiveArgumentType(node, i) ||
// for the argument. In that case, we should check the argument. checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
if (argType === undefined) { // If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter),
argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); // we obtain the regular type of any object literal arguments because we may not have inferred complete
} // parameter types yet and therefore excess property checks may yield false positives (see #17041).
const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType;
// Use argument expression as error location when reporting errors // Use argument expression as error location when reporting errors
const errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined; const errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined;
if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage)) { if (!checkTypeRelatedTo(checkArgType, paramType, relation, errorNode, headMessage)) {
return false; return false;
} }
} }
@ -15620,6 +15620,7 @@ namespace ts {
// For a decorator, no arguments are susceptible to contextual typing due to the fact // For a decorator, no arguments are susceptible to contextual typing due to the fact
// decorators are applied to a declaration by the emitter, and not to an expression. // decorators are applied to a declaration by the emitter, and not to an expression.
let excludeArgument: boolean[]; let excludeArgument: boolean[];
let excludeCount = 0;
if (!isDecorator) { if (!isDecorator) {
// We do not need to call `getEffectiveArgumentCount` here as it only // We do not need to call `getEffectiveArgumentCount` here as it only
// applies when calculating the number of arguments for a decorator. // applies when calculating the number of arguments for a decorator.
@ -15629,6 +15630,7 @@ namespace ts {
excludeArgument = new Array(args.length); excludeArgument = new Array(args.length);
} }
excludeArgument[i] = true; excludeArgument[i] = true;
excludeCount++;
} }
} }
} }
@ -15803,12 +15805,17 @@ namespace ts {
candidateForArgumentError = candidate; candidateForArgumentError = candidate;
break; break;
} }
const index = excludeArgument ? indexOf(excludeArgument, /*value*/ true) : -1; if (excludeCount === 0) {
if (index < 0) {
candidates[candidateIndex] = candidate; candidates[candidateIndex] = candidate;
return candidate; return candidate;
} }
excludeArgument[index] = false; excludeCount--;
if (excludeCount > 0) {
excludeArgument[indexOf(excludeArgument, /*value*/ true)] = false;
}
else {
excludeArgument = undefined;
}
} }
} }