From ac447f1f513fbbe3eb16eb7f0dcaf795ef080792 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 21 May 2015 16:45:23 -0700 Subject: [PATCH 1/5] Migrated decorator checks to call resolution --- src/compiler/checker.ts | 368 +++++++++++++++--- .../diagnosticInformationMap.generated.ts | 2 + src/compiler/diagnosticMessages.json | 8 + src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 3 + .../decoratedClassFromExternalModule.js | 4 +- .../decoratedClassFromExternalModule.symbols | 5 +- .../decoratedClassFromExternalModule.types | 7 +- .../decoratorChecksFunctionBodies.errors.txt | 2 +- .../decoratorChecksFunctionBodies.js | 4 +- ...ratorInstantiateModulesInFunctionBodies.js | 4 +- ...InstantiateModulesInFunctionBodies.symbols | 3 +- ...orInstantiateModulesInFunctionBodies.types | 11 +- .../reference/decoratorOnClass8.errors.txt | 6 +- .../decoratorOnClassMethod10.errors.txt | 16 +- .../reference/decoratorOnClassMethod13.js | 2 +- .../decoratorOnClassMethod13.symbols | 16 +- .../reference/decoratorOnClassMethod13.types | 8 +- .../decoratorOnClassMethod6.errors.txt | 13 + .../reference/decoratorOnClassMethod6.symbols | 18 - .../reference/decoratorOnClassMethod6.types | 19 - .../decoratorOnClassMethod8.errors.txt | 13 + .../reference/decoratorOnClassMethod8.symbols | 15 - .../reference/decoratorOnClassMethod8.types | 15 - .../decoratorOnClassMethodParameter1.js | 2 +- .../decoratorOnClassMethodParameter1.symbols | 10 +- .../decoratorOnClassMethodParameter1.types | 10 +- .../decoratorOnClassProperty11.errors.txt | 13 + .../decoratorOnClassProperty11.symbols | 14 - .../decoratorOnClassProperty11.types | 14 - .../decoratorOnClassProperty6.errors.txt | 13 + .../decoratorOnClassProperty6.symbols | 13 - .../reference/decoratorOnClassProperty6.types | 13 - .../decoratorOnClassProperty7.errors.txt | 6 +- .../reference/missingDecoratorType.errors.txt | 22 +- .../reference/missingDecoratorType.js | 15 +- tests/baselines/reference/noEmitHelpers2.js | 3 +- .../reference/noEmitHelpers2.symbols | 10 +- .../baselines/reference/noEmitHelpers2.types | 8 +- .../sourceMapValidationDecorators.js | 4 +- ...ourceMapValidationDecorators.sourcemap.txt | 4 +- .../sourceMapValidationDecorators.symbols | 36 +- .../sourceMapValidationDecorators.types | 40 +- tests/cases/compiler/noEmitHelpers2.ts | 2 +- .../compiler/sourceMapValidationDecorators.ts | 4 +- .../class/decoratedClassFromExternalModule.ts | 2 +- .../class/decoratorChecksFunctionBodies.ts | 2 +- ...ratorInstantiateModulesInFunctionBodies.ts | 2 +- .../class/method/decoratorOnClassMethod13.ts | 2 +- .../decoratorOnClassMethodParameter1.ts | 2 +- .../decorators/missingDecoratorType.ts | 9 +- 51 files changed, 533 insertions(+), 306 deletions(-) create mode 100644 tests/baselines/reference/decoratorOnClassMethod6.errors.txt delete mode 100644 tests/baselines/reference/decoratorOnClassMethod6.symbols delete mode 100644 tests/baselines/reference/decoratorOnClassMethod6.types create mode 100644 tests/baselines/reference/decoratorOnClassMethod8.errors.txt delete mode 100644 tests/baselines/reference/decoratorOnClassMethod8.symbols delete mode 100644 tests/baselines/reference/decoratorOnClassMethod8.types create mode 100644 tests/baselines/reference/decoratorOnClassProperty11.errors.txt delete mode 100644 tests/baselines/reference/decoratorOnClassProperty11.symbols delete mode 100644 tests/baselines/reference/decoratorOnClassProperty11.types create mode 100644 tests/baselines/reference/decoratorOnClassProperty6.errors.txt delete mode 100644 tests/baselines/reference/decoratorOnClassProperty6.symbols delete mode 100644 tests/baselines/reference/decoratorOnClassProperty6.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9bd0d6475fe..e99dd7eeb4e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -114,10 +114,7 @@ module ts { let globalIterableType: ObjectType; let anyArrayType: Type; - let getGlobalClassDecoratorType: () => ObjectType; - let getGlobalParameterDecoratorType: () => ObjectType; - let getGlobalPropertyDecoratorType: () => ObjectType; - let getGlobalMethodDecoratorType: () => ObjectType; + let getGlobalTypedPropertyDescriptorType: () => ObjectType; let tupleTypes: Map = {}; let unionTypes: Map = {}; @@ -3975,8 +3972,8 @@ module ts { return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain); } - function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage): boolean { - return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage); + function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean { + return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain); } function isSignatureAssignableTo(source: Signature, target: Signature): boolean { @@ -6539,7 +6536,7 @@ module ts { if (node.kind === SyntaxKind.TaggedTemplateExpression) { checkExpression((node).template); } - else { + else if (node.kind !== SyntaxKind.Decorator) { forEach((node).arguments, argument => { checkExpression(argument); }); @@ -6645,6 +6642,41 @@ module ts { callIsIncomplete = !!templateLiteral.isUnterminated; } } + else if (node.kind === SyntaxKind.Decorator) { + let decorator = node; + switch (decorator.parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + // A class decorator will have one argument (see `ClassDecorator` in core.d.ts) + adjustedArgCount = 1; + typeArguments = undefined; + break; + + case SyntaxKind.PropertyDeclaration: + // A property declaration decorator will have two arguments (see + // `PropertyDecorator` in core.d.ts) + adjustedArgCount = 2; + typeArguments = undefined; + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // A method or accessor declaration decorator will have two or three arguments (see + // `MethodDecorator` in core.d.ts) + adjustedArgCount = signature.parameters.length >= 3 ? 3 : 2; + typeArguments = undefined; + break; + + case SyntaxKind.Parameter: + // A parameter declaration decorator will have three arguments (see + // `ParameterDecorator` in core.d.ts) + + adjustedArgCount = 3; + typeArguments = undefined; + break; + } + } else { let callExpression = node; if (!callExpression.arguments) { @@ -6742,11 +6774,8 @@ module ts { let arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { let paramType = getTypeAtPosition(signature, i); - let argType: Type; - if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) { - argType = globalTemplateStringsArrayType; - } - else { + let argType = getSyntheticArgumentType(i, arg); + if (argType === undefined) { // For context sensitive arguments we pass the identityMapper, which is a signal to treat all // context sensitive function expressions as wildcards let mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; @@ -6773,7 +6802,7 @@ module ts { getInferredTypes(context); } - function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean { + function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean, containingMessageChain?: DiagnosticMessageChain): boolean { let typeParameters = signature.typeParameters; let typeArgumentsAreAssignable = true; for (let i = 0; i < typeParameters.length; i++) { @@ -6785,14 +6814,147 @@ module ts { let constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined, - Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, containingMessageChain); } } } return typeArgumentsAreAssignable; } + + function getTypeOfParentOfClassElement(node: ClassElement) { + let classSymbol = getSymbolOfNode(node.parent); + if (node.flags & NodeFlags.Static) { + return getTypeOfSymbol(classSymbol); + } + else { + return getDeclaredTypeOfSymbol(classSymbol); + } + } + + function createTypedPropertyDescriptorType(propertyType: Type): Type { + let globalTypedPropertyDescriptorType = getGlobalTypedPropertyDescriptorType(); + return globalTypedPropertyDescriptorType !== emptyObjectType + ? createTypeReference(globalTypedPropertyDescriptorType, [propertyType]) + : emptyObjectType; + } + + /** + * Gets the type for a synthetic argument when resolving the first argument for a TaggedTemplateExpression + * or any arguments to a Decorator. + */ + function getSyntheticArgumentType(argumentIndex: number, arg: Expression): Type { + if (arg.parent.kind === SyntaxKind.Decorator) { + let decorator = arg.parent; + let parent = decorator.parent; + if (argumentIndex === 0) { + // The first argument to a decorator is its `target`. + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + let classSymbol = getSymbolOfNode(parent); + return getTypeOfSymbol(classSymbol); + + case SyntaxKind.Parameter: + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + parent = parent.parent; + if (parent.kind === SyntaxKind.Constructor) { + let classSymbol = getSymbolOfNode(parent); + return getTypeOfSymbol(classSymbol); + } + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getTypeOfParentOfClassElement(parent); + } + } + else if (argumentIndex === 1) { + // The second argument to a decorator is its `propertyKey` + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a second synthetic argument."); + + case SyntaxKind.Parameter: + parent = parent.parent; + if (parent.kind === SyntaxKind.Constructor) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } + + // For a non-constructor parameter decorator, the `propertyKey` will be either + // a string or a symbol, based on the name of the parameter's containing method. + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + let element = decorator.parent; + switch (element.name.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + return getStringLiteralType(element.name); + + case SyntaxKind.ComputedPropertyName: + let nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { + return nameType; + } + else { + return stringType; + } + } + } + } + else if (argumentIndex === 2) { + // The third argument to a decorator is either its `descriptor` for a method decorator + // or its `parameterIndex` for a paramter decorator + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a third synthetic argument."); + break; - function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) { + case SyntaxKind.Parameter: + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + + case SyntaxKind.PropertyDeclaration: + Debug.fail("Property decorators should not have a third synthetic argument."); + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + let propertyType: Type = getTypeOfNode(parent); + return createTypedPropertyDescriptorType(propertyType); + } + } + } + else if (argumentIndex === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { + return globalTemplateStringsArrayType; + } + + return undefined; + } + + function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean, containingMessageChain?: DiagnosticMessageChain) { for (let i = 0; i < args.length; i++) { let arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { @@ -6800,15 +6962,16 @@ module ts { let paramType = getTypeAtPosition(signature, i); // A tagged template expression provides a special first argument, and string literals get string literal types // unless we're reporting errors - let argType = i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression - ? globalTemplateStringsArrayType - : arg.kind === SyntaxKind.StringLiteral && !reportErrors + let argType = getSyntheticArgumentType(i, arg); + if (argType === undefined) { + argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors ? getStringLiteralType(arg) : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + } // Use argument expression as error location when reporting errors if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) { + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1, containingMessageChain)) { return false; } } @@ -6822,6 +6985,8 @@ module ts { * If 'node' is a CallExpression or a NewExpression, then its argument list is returned. * If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution * expressions, where the first element of the list is the template for error reporting purposes. + * If 'node' is a Decorator, a new argument list is constructed with the decorator + * expression as a placeholder. */ function getEffectiveCallArguments(node: CallLikeExpression): Expression[] { let args: Expression[]; @@ -6835,6 +7000,23 @@ module ts { }); } } + else if (node.kind === SyntaxKind.Decorator) { + let decorator = node; + switch (decorator.parent.kind) { + case SyntaxKind.ClassDeclaration: + args = [decorator.expression]; + break; + case SyntaxKind.PropertyDeclaration: + args = [decorator.expression, decorator.expression]; + break; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Parameter: + args = [decorator.expression, decorator.expression, decorator.expression]; + break; + } + } else { args = (node).arguments || emptyArray; } @@ -6863,13 +7045,14 @@ module ts { return callExpression.typeArguments; } } - - function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature { + + function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], containingMessageChain?: DiagnosticMessageChain): Signature { let isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; + let isDecorator = node.kind === SyntaxKind.Decorator; let typeArguments: TypeNode[]; - if (!isTaggedTemplate) { + if (!isTaggedTemplate && !isDecorator) { typeArguments = getEffectiveTypeArguments(node); // We already perform checking on the type arguments on the class declaration itself. @@ -6882,7 +7065,7 @@ module ts { // reorderCandidates fills up the candidates array directly reorderCandidates(signatures, candidates); if (!candidates.length) { - error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + reportError(Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); return resolveErrorCall(node); } @@ -6900,12 +7083,14 @@ module ts { // For a tagged template, then the first argument be 'undefined' if necessary // because it represents a TemplateStringsArray. let excludeArgument: boolean[]; - for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { - if (isContextSensitive(args[i])) { - if (!excludeArgument) { - excludeArgument = new Array(args.length); + if (!isDecorator) { + for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { + if (isContextSensitive(args[i])) { + if (!excludeArgument) { + excludeArgument = new Array(args.length); + } + excludeArgument[i] = true; } - excludeArgument[i] = true; } } @@ -6969,11 +7154,11 @@ module ts { // in arguments too early. If possible, we'd like to only type them once we know the correct // overload. However, this matters for the case where the call is correct. When the call is // an error, we don't need to exclude any arguments, although it would cause no harm to do so. - checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true); + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true, containingMessageChain); } else if (candidateForTypeArgumentError) { - if (!isTaggedTemplate && (node).typeArguments) { - checkTypeArguments(candidateForTypeArgumentError, (node).typeArguments, [], /*reportErrors*/ true) + if (!isTaggedTemplate && !isDecorator && (node).typeArguments) { + checkTypeArguments(candidateForTypeArgumentError, (node).typeArguments, [], /*reportErrors*/ true, containingMessageChain) } else { Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); @@ -6983,12 +7168,16 @@ module ts { let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, // details will be provided by call to reportNoCommonSupertypeError Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly, typeToString(failedTypeParameter)); + + if (containingMessageChain) { + diagnosticChainHead = concatenateDiagnosticMessageChains(containingMessageChain, diagnosticChainHead); + } reportNoCommonSupertypeError(inferenceCandidates, (node).expression || (node).tag, diagnosticChainHead); } } else { - error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + reportError(Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); } // No signature was applicable. We have already reported the errors for the invalid signature. @@ -7005,6 +7194,15 @@ module ts { } return resolveErrorCall(node); + + function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void { + let errorInfo = chainDiagnosticMessages(/*details*/ undefined, message, arg0, arg1, arg2); + if (containingMessageChain) { + errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo); + } + + diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo)); + } function chooseOverload(candidates: Signature[], relation: Map) { for (let originalCandidate of candidates) { @@ -7205,6 +7403,55 @@ module ts { return resolveCall(node, callSignatures, candidatesOutArray); } + function resolveDecorator(node: Decorator, candidatesOutArray: Signature[]): Signature { + let funcType = checkExpression(node.expression); + let apparentType = getApparentType(funcType); + if (apparentType === unknownType) { + return resolveErrorCall(node); + } + + let callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); + if (funcType === anyType || (!callSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { + return resolveUntypedCall(node); + } + + let decoratorKind: string; + switch (node.parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + decoratorKind = "class"; + break; + + case SyntaxKind.Parameter: + decoratorKind = "parameter"; + break; + + case SyntaxKind.PropertyDeclaration: + decoratorKind = "property"; + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + decoratorKind = "method"; + break; + + default: + Debug.fail("Invalid decorator target."); + break; + } + + let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Invalid_expression_for_0_decorator, decoratorKind); + if (!callSignatures.length) { + let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + errorInfo = concatenateDiagnosticMessageChains(diagnosticChainHead, errorInfo); + diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo)); + return resolveErrorCall(node); + } + + return resolveCall(node, callSignatures, candidatesOutArray, diagnosticChainHead); + } + // candidatesOutArray is passed by signature help in the language service, and collectCandidates // must fill it up with the appropriate candidate signatures function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature { @@ -7225,6 +7472,9 @@ module ts { else if (node.kind === SyntaxKind.TaggedTemplateExpression) { links.resolvedSignature = resolveTaggedTemplateExpression(node, candidatesOutArray); } + else if (node.kind === SyntaxKind.Decorator) { + links.resolvedSignature = resolveDecorator(node, candidatesOutArray); + } else { Debug.fail("Branch in 'getResolvedSignature' should be unreachable."); } @@ -8844,35 +9094,58 @@ module ts { /** Check a decorator */ function checkDecorator(node: Decorator): void { - let expression: Expression = node.expression; - let exprType = checkExpression(expression); - + let signature = getResolvedSignature(node); + let returnType = getReturnTypeOfSignature(signature); + if (returnType.flags & TypeFlags.Any) { + return; + } + + let expectedReturnType: Type; + let diagnosticChainHead: DiagnosticMessageChain; + let decoratorKind: string; switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: let classSymbol = getSymbolOfNode(node.parent); let classConstructorType = getTypeOfSymbol(classSymbol); - let classDecoratorType = instantiateSingleCallFunctionType(getGlobalClassDecoratorType(), [classConstructorType]); - checkTypeAssignableTo(exprType, classDecoratorType, node); + expectedReturnType = getUnionType([classConstructorType, voidType]); + decoratorKind = "class"; + break; + + case SyntaxKind.Parameter: + expectedReturnType = voidType; + decoratorKind = "parameter"; break; case SyntaxKind.PropertyDeclaration: - checkTypeAssignableTo(exprType, getGlobalPropertyDecoratorType(), node); + expectedReturnType = voidType; + decoratorKind = "property"; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: let methodType = getTypeOfNode(node.parent); - let methodDecoratorType = instantiateSingleCallFunctionType(getGlobalMethodDecoratorType(), [methodType]); - checkTypeAssignableTo(exprType, methodDecoratorType, node); - break; - - case SyntaxKind.Parameter: - checkTypeAssignableTo(exprType, getGlobalParameterDecoratorType(), node); + let descriptorType = createTypedPropertyDescriptorType(methodType); + expectedReturnType = getUnionType([descriptorType, voidType]); + decoratorKind = "method"; break; } + + if (expectedReturnType === voidType) { + diagnosticChainHead = chainDiagnosticMessages( + diagnosticChainHead, + Diagnostics.The_return_type_of_a_0_decorator_function_must_be_either_void_or_any, + decoratorKind); + } + + diagnosticChainHead = chainDiagnosticMessages( + diagnosticChainHead, + Diagnostics.Invalid_expression_for_0_decorator, + decoratorKind); + + checkTypeAssignableTo(returnType, expectedReturnType, node, /*headMessage*/ undefined, diagnosticChainHead); } - + /** Checks a type reference node as an expression. */ function checkTypeNodeAsExpression(node: TypeNode) { // When we are emitting type metadata for decorators, we need to try to check the type @@ -12043,10 +12316,7 @@ module ts { globalNumberType = getGlobalType("Number"); globalBooleanType = getGlobalType("Boolean"); globalRegExpType = getGlobalType("RegExp"); - getGlobalClassDecoratorType = memoize(() => getGlobalType("ClassDecorator")); - getGlobalPropertyDecoratorType = memoize(() => getGlobalType("PropertyDecorator")); - getGlobalMethodDecoratorType = memoize(() => getGlobalType("MethodDecorator")); - getGlobalParameterDecoratorType = memoize(() => getGlobalType("ParameterDecorator")); + getGlobalTypedPropertyDescriptorType = memoize(() => getGlobalType("TypedPropertyDescriptor", /*arity*/ 1)); // If we're in ES6 mode, load the TemplateStringsArray. // Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios. diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 2a852716846..1eaf69d8886 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -174,6 +174,8 @@ module ts { Type_expected_0_is_a_reserved_word_in_strict_mode: { code: 1215, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode" }, Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, Export_assignment_is_not_supported_when_module_flag_is_system: { code: 1218, category: DiagnosticCategory.Error, key: "Export assignment is not supported when '--module' flag is 'system'." }, + The_return_type_of_a_0_decorator_function_must_be_either_void_or_any: { code: 1219, category: DiagnosticCategory.Error, key: "The return type of a {0} decorator function must be either 'void' or 'any'." }, + Invalid_expression_for_0_decorator: { code: 1220, category: DiagnosticCategory.Error, key: "Invalid expression for {0} decorator." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index cf1645b1407..36f7505fc65 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -683,6 +683,14 @@ "category": "Error", "code": 1218 }, + "The return type of a {0} decorator function must be either 'void' or 'any'.": { + "category": "Error", + "code": 1219 + }, + "Invalid expression for {0} decorator.": { + "category": "Error", + "code": 1220 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 86e680ca8b0..2c63241fdf2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -753,7 +753,7 @@ module ts { template: LiteralExpression | TemplateExpression; } - export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression; + export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator; export interface TypeAssertion extends UnaryExpression { type: TypeNode; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 356337e1315..e720c7a112e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -620,6 +620,9 @@ module ts { if (node.kind === SyntaxKind.TaggedTemplateExpression) { return (node).tag; } + else if (node.kind === SyntaxKind.Decorator) { + return (node).expression; + } // Will either be a CallExpression or NewExpression. return (node).expression; diff --git a/tests/baselines/reference/decoratedClassFromExternalModule.js b/tests/baselines/reference/decoratedClassFromExternalModule.js index 163a4a094b4..aca1d28b952 100644 --- a/tests/baselines/reference/decoratedClassFromExternalModule.js +++ b/tests/baselines/reference/decoratedClassFromExternalModule.js @@ -1,7 +1,7 @@ //// [tests/cases/conformance/decorators/class/decoratedClassFromExternalModule.ts] //// //// [decorated.ts] -function decorate() { } +function decorate(target: any) { } @decorate export default class Decorated { } @@ -18,7 +18,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); } }; -function decorate() { } +function decorate(target) { } let Decorated = class { }; Decorated = __decorate([ diff --git a/tests/baselines/reference/decoratedClassFromExternalModule.symbols b/tests/baselines/reference/decoratedClassFromExternalModule.symbols index aa17dde616a..60e4a892ec0 100644 --- a/tests/baselines/reference/decoratedClassFromExternalModule.symbols +++ b/tests/baselines/reference/decoratedClassFromExternalModule.symbols @@ -1,12 +1,13 @@ === tests/cases/conformance/decorators/class/decorated.ts === -function decorate() { } +function decorate(target: any) { } >decorate : Symbol(decorate, Decl(decorated.ts, 0, 0)) +>target : Symbol(target, Decl(decorated.ts, 0, 18)) @decorate >decorate : Symbol(decorate, Decl(decorated.ts, 0, 0)) export default class Decorated { } ->Decorated : Symbol(Decorated, Decl(decorated.ts, 0, 23)) +>Decorated : Symbol(Decorated, Decl(decorated.ts, 0, 34)) === tests/cases/conformance/decorators/class/undecorated.ts === import Decorated from 'decorated'; diff --git a/tests/baselines/reference/decoratedClassFromExternalModule.types b/tests/baselines/reference/decoratedClassFromExternalModule.types index 4234b6a4b15..d4bc3239e46 100644 --- a/tests/baselines/reference/decoratedClassFromExternalModule.types +++ b/tests/baselines/reference/decoratedClassFromExternalModule.types @@ -1,9 +1,10 @@ === tests/cases/conformance/decorators/class/decorated.ts === -function decorate() { } ->decorate : () => void +function decorate(target: any) { } +>decorate : (target: any) => void +>target : any @decorate ->decorate : () => void +>decorate : (target: any) => void export default class Decorated { } >Decorated : Decorated diff --git a/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt b/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt index c8166b538fd..cef2f90f704 100644 --- a/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt +++ b/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt @@ -8,7 +8,7 @@ tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts(9,14): } class A { - @(x => { + @((x, p) => { var a = 3; func(a); ~ diff --git a/tests/baselines/reference/decoratorChecksFunctionBodies.js b/tests/baselines/reference/decoratorChecksFunctionBodies.js index 020bc775aea..adb710efccc 100644 --- a/tests/baselines/reference/decoratorChecksFunctionBodies.js +++ b/tests/baselines/reference/decoratorChecksFunctionBodies.js @@ -5,7 +5,7 @@ function func(s: string): void { } class A { - @(x => { + @((x, p) => { var a = 3; func(a); return x; @@ -34,7 +34,7 @@ var A = (function () { }; Object.defineProperty(A.prototype, "m", __decorate([ - (function (x) { + (function (x, p) { var a = 3; func(a); return x; diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js index 313d77fa5ce..08ba6e9ea7e 100644 --- a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js @@ -9,7 +9,7 @@ export var test = 'abc'; import { test } from './a'; function filter(handler: any) { - return function (target: any) { + return function (target: any, propertyKey: string) { // ... }; } @@ -35,7 +35,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, }; var a_1 = require('./a'); function filter(handler) { - return function (target) { + return function (target, propertyKey) { // ... }; } diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols index 5088e740a57..f7c96097caf 100644 --- a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols @@ -12,8 +12,9 @@ function filter(handler: any) { >filter : Symbol(filter, Decl(b.ts, 0, 27)) >handler : Symbol(handler, Decl(b.ts, 2, 16)) - return function (target: any) { + return function (target: any, propertyKey: string) { >target : Symbol(target, Decl(b.ts, 3, 21)) +>propertyKey : Symbol(propertyKey, Decl(b.ts, 3, 33)) // ... }; diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types index 18d993af9bb..d0f930b7ad4 100644 --- a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types @@ -10,12 +10,13 @@ import { test } from './a'; >test : string function filter(handler: any) { ->filter : (handler: any) => (target: any) => void +>filter : (handler: any) => (target: any, propertyKey: string) => void >handler : any - return function (target: any) { ->function (target: any) { // ... } : (target: any) => void + return function (target: any, propertyKey: string) { +>function (target: any, propertyKey: string) { // ... } : (target: any, propertyKey: string) => void >target : any +>propertyKey : string // ... }; @@ -25,8 +26,8 @@ class Wat { >Wat : Wat @filter(() => test == 'abc') ->filter(() => test == 'abc') : (target: any) => void ->filter : (handler: any) => (target: any) => void +>filter(() => test == 'abc') : (target: any, propertyKey: string) => void +>filter : (handler: any) => (target: any, propertyKey: string) => void >() => test == 'abc' : () => boolean >test == 'abc' : boolean >test : string diff --git a/tests/baselines/reference/decoratorOnClass8.errors.txt b/tests/baselines/reference/decoratorOnClass8.errors.txt index 0a9fbf2956c..31abd9e2300 100644 --- a/tests/baselines/reference/decoratorOnClass8.errors.txt +++ b/tests/baselines/reference/decoratorOnClass8.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS2322: Type '(target: Function, paramIndex: number) => void' is not assignable to type '(target: typeof C) => void | typeof C'. +tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220: Invalid expression for class decorator. + Supplied parameters do not match any signature of call target. ==== tests/cases/conformance/decorators/class/decoratorOnClass8.ts (1 errors) ==== @@ -6,6 +7,7 @@ tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS2322 @dec() ~~~~~~ -!!! error TS2322: Type '(target: Function, paramIndex: number) => void' is not assignable to type '(target: typeof C) => void | typeof C'. +!!! error TS1220: Invalid expression for class decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. class C { } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt index cd331473b7c..bfc56717e6c 100644 --- a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt @@ -1,7 +1,6 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,5): error TS2322: Type '(target: Function, paramIndex: number) => void' is not assignable to type '(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<() => void>) => void | TypedPropertyDescriptor<() => void>'. - Types of parameters 'paramIndex' and 'propertyKey' are incompatible. - Type 'number' is not assignable to type 'string | symbol'. - Type 'number' is not assignable to type 'symbol'. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6): error TS1220: Invalid expression for method decorator. + Argument of type 'C' is not assignable to parameter of type 'Function'. + Property 'apply' is missing in type 'C'. ==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts (1 errors) ==== @@ -9,9 +8,8 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,5) class C { @dec method() {} - ~~~~ -!!! error TS2322: Type '(target: Function, paramIndex: number) => void' is not assignable to type '(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<() => void>) => void | TypedPropertyDescriptor<() => void>'. -!!! error TS2322: Types of parameters 'paramIndex' and 'propertyKey' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string | symbol'. -!!! error TS2322: Type 'number' is not assignable to type 'symbol'. + ~~~ +!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Argument of type 'C' is not assignable to parameter of type 'Function'. +!!! error TS1220: Property 'apply' is missing in type 'C'. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod13.js b/tests/baselines/reference/decoratorOnClassMethod13.js index 967cc05ba4d..b39fa63686a 100644 --- a/tests/baselines/reference/decoratorOnClassMethod13.js +++ b/tests/baselines/reference/decoratorOnClassMethod13.js @@ -1,5 +1,5 @@ //// [decoratorOnClassMethod13.ts] -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; +declare function dec(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; class C { @dec ["1"]() { } diff --git a/tests/baselines/reference/decoratorOnClassMethod13.symbols b/tests/baselines/reference/decoratorOnClassMethod13.symbols index af3819924f4..42f44d885ee 100644 --- a/tests/baselines/reference/decoratorOnClassMethod13.symbols +++ b/tests/baselines/reference/decoratorOnClassMethod13.symbols @@ -1,17 +1,17 @@ === tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts === -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; +declare function dec(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; >dec : Symbol(dec, Decl(decoratorOnClassMethod13.ts, 0, 0)) ->T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 25)) ->target : Symbol(target, Decl(decoratorOnClassMethod13.ts, 0, 28)) ->propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethod13.ts, 0, 40)) ->descriptor : Symbol(descriptor, Decl(decoratorOnClassMethod13.ts, 0, 61)) +>T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 21)) +>target : Symbol(target, Decl(decoratorOnClassMethod13.ts, 0, 24)) +>propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethod13.ts, 0, 36)) +>descriptor : Symbol(descriptor, Decl(decoratorOnClassMethod13.ts, 0, 57)) >TypedPropertyDescriptor : Symbol(TypedPropertyDescriptor, Decl(lib.d.ts, 1171, 36)) ->T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 25)) +>T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 21)) >TypedPropertyDescriptor : Symbol(TypedPropertyDescriptor, Decl(lib.d.ts, 1171, 36)) ->T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 25)) +>T : Symbol(T, Decl(decoratorOnClassMethod13.ts, 0, 21)) class C { ->C : Symbol(C, Decl(decoratorOnClassMethod13.ts, 0, 132)) +>C : Symbol(C, Decl(decoratorOnClassMethod13.ts, 0, 126)) @dec ["1"]() { } >dec : Symbol(dec, Decl(decoratorOnClassMethod13.ts, 0, 0)) diff --git a/tests/baselines/reference/decoratorOnClassMethod13.types b/tests/baselines/reference/decoratorOnClassMethod13.types index 2858f8877bd..5fdbe071828 100644 --- a/tests/baselines/reference/decoratorOnClassMethod13.types +++ b/tests/baselines/reference/decoratorOnClassMethod13.types @@ -1,6 +1,6 @@ === tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts === -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; ->dec : () => (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor +declare function dec(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; +>dec : (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor >T : T >target : any >propertyKey : string @@ -14,10 +14,10 @@ class C { >C : C @dec ["1"]() { } ->dec : () => (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor +>dec : (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor >"1" : string @dec ["b"]() { } ->dec : () => (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor +>dec : (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor >"b" : string } diff --git a/tests/baselines/reference/decoratorOnClassMethod6.errors.txt b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt new file mode 100644 index 00000000000..ade416aefbc --- /dev/null +++ b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1220: Invalid expression for method decorator. + Supplied parameters do not match any signature of call target. + + +==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts (1 errors) ==== + declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; + + class C { + @dec ["method"]() {} + ~~~~ +!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod6.symbols b/tests/baselines/reference/decoratorOnClassMethod6.symbols deleted file mode 100644 index 8dcdd99a8e9..00000000000 --- a/tests/baselines/reference/decoratorOnClassMethod6.symbols +++ /dev/null @@ -1,18 +0,0 @@ -=== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts === -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; ->dec : Symbol(dec, Decl(decoratorOnClassMethod6.ts, 0, 0)) ->T : Symbol(T, Decl(decoratorOnClassMethod6.ts, 0, 25)) ->target : Symbol(target, Decl(decoratorOnClassMethod6.ts, 0, 28)) ->propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethod6.ts, 0, 40)) ->descriptor : Symbol(descriptor, Decl(decoratorOnClassMethod6.ts, 0, 61)) ->TypedPropertyDescriptor : Symbol(TypedPropertyDescriptor, Decl(lib.d.ts, 1171, 36)) ->T : Symbol(T, Decl(decoratorOnClassMethod6.ts, 0, 25)) ->TypedPropertyDescriptor : Symbol(TypedPropertyDescriptor, Decl(lib.d.ts, 1171, 36)) ->T : Symbol(T, Decl(decoratorOnClassMethod6.ts, 0, 25)) - -class C { ->C : Symbol(C, Decl(decoratorOnClassMethod6.ts, 0, 132)) - - @dec ["method"]() {} ->dec : Symbol(dec, Decl(decoratorOnClassMethod6.ts, 0, 0)) -} diff --git a/tests/baselines/reference/decoratorOnClassMethod6.types b/tests/baselines/reference/decoratorOnClassMethod6.types deleted file mode 100644 index 9da71791763..00000000000 --- a/tests/baselines/reference/decoratorOnClassMethod6.types +++ /dev/null @@ -1,19 +0,0 @@ -=== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts === -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; ->dec : () => (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor ->T : T ->target : any ->propertyKey : string ->descriptor : TypedPropertyDescriptor ->TypedPropertyDescriptor : TypedPropertyDescriptor ->T : T ->TypedPropertyDescriptor : TypedPropertyDescriptor ->T : T - -class C { ->C : C - - @dec ["method"]() {} ->dec : () => (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor ->"method" : string -} diff --git a/tests/baselines/reference/decoratorOnClassMethod8.errors.txt b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt new file mode 100644 index 00000000000..d0635b4f5f3 --- /dev/null +++ b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): error TS1220: Invalid expression for method decorator. + Supplied parameters do not match any signature of call target. + + +==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts (1 errors) ==== + declare function dec(target: T): T; + + class C { + @dec method() {} + ~~~~ +!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod8.symbols b/tests/baselines/reference/decoratorOnClassMethod8.symbols deleted file mode 100644 index 84b68b81421..00000000000 --- a/tests/baselines/reference/decoratorOnClassMethod8.symbols +++ /dev/null @@ -1,15 +0,0 @@ -=== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts === -declare function dec(target: T): T; ->dec : Symbol(dec, Decl(decoratorOnClassMethod8.ts, 0, 0)) ->T : Symbol(T, Decl(decoratorOnClassMethod8.ts, 0, 21)) ->target : Symbol(target, Decl(decoratorOnClassMethod8.ts, 0, 24)) ->T : Symbol(T, Decl(decoratorOnClassMethod8.ts, 0, 21)) ->T : Symbol(T, Decl(decoratorOnClassMethod8.ts, 0, 21)) - -class C { ->C : Symbol(C, Decl(decoratorOnClassMethod8.ts, 0, 38)) - - @dec method() {} ->dec : Symbol(dec, Decl(decoratorOnClassMethod8.ts, 0, 0)) ->method : Symbol(method, Decl(decoratorOnClassMethod8.ts, 2, 9)) -} diff --git a/tests/baselines/reference/decoratorOnClassMethod8.types b/tests/baselines/reference/decoratorOnClassMethod8.types deleted file mode 100644 index 20890b09846..00000000000 --- a/tests/baselines/reference/decoratorOnClassMethod8.types +++ /dev/null @@ -1,15 +0,0 @@ -=== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts === -declare function dec(target: T): T; ->dec : (target: T) => T ->T : T ->target : T ->T : T ->T : T - -class C { ->C : C - - @dec method() {} ->dec : (target: T) => T ->method : () => void -} diff --git a/tests/baselines/reference/decoratorOnClassMethodParameter1.js b/tests/baselines/reference/decoratorOnClassMethodParameter1.js index 4a3ed36eec5..a6ab1704acc 100644 --- a/tests/baselines/reference/decoratorOnClassMethodParameter1.js +++ b/tests/baselines/reference/decoratorOnClassMethodParameter1.js @@ -1,5 +1,5 @@ //// [decoratorOnClassMethodParameter1.ts] -declare function dec(target: Function, propertyKey: string | symbol, parameterIndex: number): void; +declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void; class C { method(@dec p: number) {} diff --git a/tests/baselines/reference/decoratorOnClassMethodParameter1.symbols b/tests/baselines/reference/decoratorOnClassMethodParameter1.symbols index 0ced8829766..47c5999ff47 100644 --- a/tests/baselines/reference/decoratorOnClassMethodParameter1.symbols +++ b/tests/baselines/reference/decoratorOnClassMethodParameter1.symbols @@ -1,13 +1,13 @@ === tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts === -declare function dec(target: Function, propertyKey: string | symbol, parameterIndex: number): void; +declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void; >dec : Symbol(dec, Decl(decoratorOnClassMethodParameter1.ts, 0, 0)) >target : Symbol(target, Decl(decoratorOnClassMethodParameter1.ts, 0, 21)) ->Function : Symbol(Function, Decl(lib.d.ts, 223, 38), Decl(lib.d.ts, 269, 11)) ->propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethodParameter1.ts, 0, 38)) ->parameterIndex : Symbol(parameterIndex, Decl(decoratorOnClassMethodParameter1.ts, 0, 68)) +>Object : Symbol(Object, Decl(lib.d.ts, 92, 1), Decl(lib.d.ts, 223, 11)) +>propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethodParameter1.ts, 0, 36)) +>parameterIndex : Symbol(parameterIndex, Decl(decoratorOnClassMethodParameter1.ts, 0, 66)) class C { ->C : Symbol(C, Decl(decoratorOnClassMethodParameter1.ts, 0, 99)) +>C : Symbol(C, Decl(decoratorOnClassMethodParameter1.ts, 0, 97)) method(@dec p: number) {} >method : Symbol(method, Decl(decoratorOnClassMethodParameter1.ts, 2, 9)) diff --git a/tests/baselines/reference/decoratorOnClassMethodParameter1.types b/tests/baselines/reference/decoratorOnClassMethodParameter1.types index 0b75471471f..74aa04a8985 100644 --- a/tests/baselines/reference/decoratorOnClassMethodParameter1.types +++ b/tests/baselines/reference/decoratorOnClassMethodParameter1.types @@ -1,8 +1,8 @@ === tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts === -declare function dec(target: Function, propertyKey: string | symbol, parameterIndex: number): void; ->dec : (target: Function, propertyKey: string | symbol, parameterIndex: number) => void ->target : Function ->Function : Function +declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void; +>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void +>target : Object +>Object : Object >propertyKey : string | symbol >parameterIndex : number @@ -11,6 +11,6 @@ class C { method(@dec p: number) {} >method : (p: number) => void ->dec : (target: Function, propertyKey: string | symbol, parameterIndex: number) => void +>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void >p : number } diff --git a/tests/baselines/reference/decoratorOnClassProperty11.errors.txt b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt new file mode 100644 index 00000000000..92b89b0b430 --- /dev/null +++ b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1220: Invalid expression for property decorator. + Supplied parameters do not match any signature of call target. + + +==== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts (1 errors) ==== + declare function dec(): (target: any, propertyKey: string) => void; + + class C { + @dec prop; + ~~~~ +!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty11.symbols b/tests/baselines/reference/decoratorOnClassProperty11.symbols deleted file mode 100644 index c7d6e39c713..00000000000 --- a/tests/baselines/reference/decoratorOnClassProperty11.symbols +++ /dev/null @@ -1,14 +0,0 @@ -=== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts === -declare function dec(): (target: any, propertyKey: string) => void; ->dec : Symbol(dec, Decl(decoratorOnClassProperty11.ts, 0, 0)) ->T : Symbol(T, Decl(decoratorOnClassProperty11.ts, 0, 25)) ->target : Symbol(target, Decl(decoratorOnClassProperty11.ts, 0, 28)) ->propertyKey : Symbol(propertyKey, Decl(decoratorOnClassProperty11.ts, 0, 40)) - -class C { ->C : Symbol(C, Decl(decoratorOnClassProperty11.ts, 0, 70)) - - @dec prop; ->dec : Symbol(dec, Decl(decoratorOnClassProperty11.ts, 0, 0)) ->prop : Symbol(prop, Decl(decoratorOnClassProperty11.ts, 2, 9)) -} diff --git a/tests/baselines/reference/decoratorOnClassProperty11.types b/tests/baselines/reference/decoratorOnClassProperty11.types deleted file mode 100644 index 5caa467d3ba..00000000000 --- a/tests/baselines/reference/decoratorOnClassProperty11.types +++ /dev/null @@ -1,14 +0,0 @@ -=== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts === -declare function dec(): (target: any, propertyKey: string) => void; ->dec : () => (target: any, propertyKey: string) => void ->T : T ->target : any ->propertyKey : string - -class C { ->C : C - - @dec prop; ->dec : () => (target: any, propertyKey: string) => void ->prop : any -} diff --git a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt new file mode 100644 index 00000000000..441ff38a421 --- /dev/null +++ b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4,5): error TS1220: Invalid expression for property decorator. + Supplied parameters do not match any signature of call target. + + +==== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts (1 errors) ==== + declare function dec(target: Function): void; + + class C { + @dec prop; + ~~~~ +!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty6.symbols b/tests/baselines/reference/decoratorOnClassProperty6.symbols deleted file mode 100644 index 7b9857e0a19..00000000000 --- a/tests/baselines/reference/decoratorOnClassProperty6.symbols +++ /dev/null @@ -1,13 +0,0 @@ -=== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts === -declare function dec(target: Function): void; ->dec : Symbol(dec, Decl(decoratorOnClassProperty6.ts, 0, 0)) ->target : Symbol(target, Decl(decoratorOnClassProperty6.ts, 0, 21)) ->Function : Symbol(Function, Decl(lib.d.ts, 223, 38), Decl(lib.d.ts, 269, 11)) - -class C { ->C : Symbol(C, Decl(decoratorOnClassProperty6.ts, 0, 45)) - - @dec prop; ->dec : Symbol(dec, Decl(decoratorOnClassProperty6.ts, 0, 0)) ->prop : Symbol(prop, Decl(decoratorOnClassProperty6.ts, 2, 9)) -} diff --git a/tests/baselines/reference/decoratorOnClassProperty6.types b/tests/baselines/reference/decoratorOnClassProperty6.types deleted file mode 100644 index 59d03678330..00000000000 --- a/tests/baselines/reference/decoratorOnClassProperty6.types +++ /dev/null @@ -1,13 +0,0 @@ -=== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts === -declare function dec(target: Function): void; ->dec : (target: Function) => void ->target : Function ->Function : Function - -class C { ->C : C - - @dec prop; ->dec : (target: Function) => void ->prop : any -} diff --git a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt index 8b93d0ab38e..e061ce446ac 100644 --- a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS2322: Type '(target: Function, propertyKey: string | symbol, paramIndex: number) => void' is not assignable to type '(target: Object, propertyKey: string | symbol) => void'. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS1220: Invalid expression for property decorator. + Supplied parameters do not match any signature of call target. ==== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts (1 errors) ==== @@ -7,5 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4 class C { @dec prop; ~~~~ -!!! error TS2322: Type '(target: Function, propertyKey: string | symbol, paramIndex: number) => void' is not assignable to type '(target: Object, propertyKey: string | symbol) => void'. +!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/missingDecoratorType.errors.txt b/tests/baselines/reference/missingDecoratorType.errors.txt index 0b159a8fcb2..91b54fde54a 100644 --- a/tests/baselines/reference/missingDecoratorType.errors.txt +++ b/tests/baselines/reference/missingDecoratorType.errors.txt @@ -1,7 +1,17 @@ -error TS2318: Cannot find global type 'ClassDecorator'. +error TS2318: Cannot find global type 'TypedPropertyDescriptor'. -!!! error TS2318: Cannot find global type 'ClassDecorator'. +!!! error TS2318: Cannot find global type 'TypedPropertyDescriptor'. +==== tests/cases/conformance/decorators/b.ts (0 errors) ==== + /// + declare function dec(t, k, d); + + class C { + @dec + method() {} + } + + ==== tests/cases/conformance/decorators/a.ts (0 errors) ==== interface Object { } @@ -12,12 +22,4 @@ error TS2318: Cannot find global type 'ClassDecorator'. interface Function { } interface RegExp { } interface IArguments { } - -==== tests/cases/conformance/decorators/b.ts (0 errors) ==== - declare var dec: any; - - @dec - class C { - } - \ No newline at end of file diff --git a/tests/baselines/reference/missingDecoratorType.js b/tests/baselines/reference/missingDecoratorType.js index 4460abdc798..e65ca7dc341 100644 --- a/tests/baselines/reference/missingDecoratorType.js +++ b/tests/baselines/reference/missingDecoratorType.js @@ -12,10 +12,12 @@ interface RegExp { } interface IArguments { } //// [b.ts] -declare var dec: any; +/// +declare function dec(t, k, d); -@dec class C { + @dec + method() {} } @@ -30,11 +32,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); } }; +/// var C = (function () { function C() { } - C = __decorate([ - dec - ], C); + C.prototype.method = function () { }; + Object.defineProperty(C.prototype, "method", + __decorate([ + dec + ], C.prototype, "method", Object.getOwnPropertyDescriptor(C.prototype, "method"))); return C; })(); diff --git a/tests/baselines/reference/noEmitHelpers2.js b/tests/baselines/reference/noEmitHelpers2.js index 1bd42377679..66e2ff78b64 100644 --- a/tests/baselines/reference/noEmitHelpers2.js +++ b/tests/baselines/reference/noEmitHelpers2.js @@ -1,6 +1,6 @@ //// [noEmitHelpers2.ts] -function decorator() { } +declare var decorator: any; @decorator class A { @@ -9,7 +9,6 @@ class A { } //// [noEmitHelpers2.js] -function decorator() { } var A = (function () { function A(a, b) { } diff --git a/tests/baselines/reference/noEmitHelpers2.symbols b/tests/baselines/reference/noEmitHelpers2.symbols index 3a3e3ec94c7..044026a3db7 100644 --- a/tests/baselines/reference/noEmitHelpers2.symbols +++ b/tests/baselines/reference/noEmitHelpers2.symbols @@ -1,17 +1,17 @@ === tests/cases/compiler/noEmitHelpers2.ts === -function decorator() { } ->decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) +declare var decorator: any; +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 1, 11)) @decorator ->decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 1, 11)) class A { ->A : Symbol(A, Decl(noEmitHelpers2.ts, 1, 24)) +>A : Symbol(A, Decl(noEmitHelpers2.ts, 1, 27)) constructor(a: number, @decorator b: string) { >a : Symbol(a, Decl(noEmitHelpers2.ts, 5, 16)) ->decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 1, 11)) >b : Symbol(b, Decl(noEmitHelpers2.ts, 5, 26)) } } diff --git a/tests/baselines/reference/noEmitHelpers2.types b/tests/baselines/reference/noEmitHelpers2.types index 2a5b5413a7e..14260e4f95c 100644 --- a/tests/baselines/reference/noEmitHelpers2.types +++ b/tests/baselines/reference/noEmitHelpers2.types @@ -1,17 +1,17 @@ === tests/cases/compiler/noEmitHelpers2.ts === -function decorator() { } ->decorator : () => void +declare var decorator: any; +>decorator : any @decorator ->decorator : () => void +>decorator : any class A { >A : A constructor(a: number, @decorator b: string) { >a : number ->decorator : () => void +>decorator : any >b : string } } diff --git a/tests/baselines/reference/sourceMapValidationDecorators.js b/tests/baselines/reference/sourceMapValidationDecorators.js index f858aeff586..5196d3b0dd8 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.js +++ b/tests/baselines/reference/sourceMapValidationDecorators.js @@ -3,8 +3,8 @@ declare function ClassDecorator1(target: Function): void; declare function ClassDecorator2(x: number): (target: Function) => void; declare function PropertyDecorator1(target: Object, key: string | symbol, descriptor?: PropertyDescriptor): void; declare function PropertyDecorator2(x: number): (target: Object, key: string | symbol, descriptor?: PropertyDescriptor) => void; -declare function ParameterDecorator1(target: Function, key: string | symbol, paramIndex: number): void; -declare function ParameterDecorator2(x: number): (target: Function, key: string | symbol, paramIndex: number) => void; +declare function ParameterDecorator1(target: Object, key: string | symbol, paramIndex: number): void; +declare function ParameterDecorator2(x: number): (target: Object, key: string | symbol, paramIndex: number) => void; @ClassDecorator1 @ClassDecorator2(10) diff --git a/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt b/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt index 68ad353db9f..b7036723a85 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt @@ -26,8 +26,8 @@ sourceFile:sourceMapValidationDecorators.ts >declare function ClassDecorator2(x: number): (target: Function) => void; >declare function PropertyDecorator1(target: Object, key: string | symbol, descriptor?: PropertyDescriptor): void; >declare function PropertyDecorator2(x: number): (target: Object, key: string | symbol, descriptor?: PropertyDescriptor) => void; - >declare function ParameterDecorator1(target: Function, key: string | symbol, paramIndex: number): void; - >declare function ParameterDecorator2(x: number): (target: Function, key: string | symbol, paramIndex: number) => void; + >declare function ParameterDecorator1(target: Object, key: string | symbol, paramIndex: number): void; + >declare function ParameterDecorator2(x: number): (target: Object, key: string | symbol, paramIndex: number) => void; > > 1 >Emitted(12, 1) Source(8, 1) + SourceIndex(0) diff --git a/tests/baselines/reference/sourceMapValidationDecorators.symbols b/tests/baselines/reference/sourceMapValidationDecorators.symbols index 37db95d3e05..e22afb7b7fc 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.symbols +++ b/tests/baselines/reference/sourceMapValidationDecorators.symbols @@ -27,20 +27,20 @@ declare function PropertyDecorator2(x: number): (target: Object, key: string | s >descriptor : Symbol(descriptor, Decl(sourceMapValidationDecorators.ts, 3, 86)) >PropertyDescriptor : Symbol(PropertyDescriptor, Decl(lib.d.ts, 79, 66)) -declare function ParameterDecorator1(target: Function, key: string | symbol, paramIndex: number): void; +declare function ParameterDecorator1(target: Object, key: string | symbol, paramIndex: number): void; >ParameterDecorator1 : Symbol(ParameterDecorator1, Decl(sourceMapValidationDecorators.ts, 3, 128)) >target : Symbol(target, Decl(sourceMapValidationDecorators.ts, 4, 37)) ->Function : Symbol(Function, Decl(lib.d.ts, 223, 38), Decl(lib.d.ts, 269, 11)) ->key : Symbol(key, Decl(sourceMapValidationDecorators.ts, 4, 54)) ->paramIndex : Symbol(paramIndex, Decl(sourceMapValidationDecorators.ts, 4, 76)) +>Object : Symbol(Object, Decl(lib.d.ts, 92, 1), Decl(lib.d.ts, 223, 11)) +>key : Symbol(key, Decl(sourceMapValidationDecorators.ts, 4, 52)) +>paramIndex : Symbol(paramIndex, Decl(sourceMapValidationDecorators.ts, 4, 74)) -declare function ParameterDecorator2(x: number): (target: Function, key: string | symbol, paramIndex: number) => void; ->ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 103)) +declare function ParameterDecorator2(x: number): (target: Object, key: string | symbol, paramIndex: number) => void; +>ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 101)) >x : Symbol(x, Decl(sourceMapValidationDecorators.ts, 5, 37)) >target : Symbol(target, Decl(sourceMapValidationDecorators.ts, 5, 50)) ->Function : Symbol(Function, Decl(lib.d.ts, 223, 38), Decl(lib.d.ts, 269, 11)) ->key : Symbol(key, Decl(sourceMapValidationDecorators.ts, 5, 67)) ->paramIndex : Symbol(paramIndex, Decl(sourceMapValidationDecorators.ts, 5, 89)) +>Object : Symbol(Object, Decl(lib.d.ts, 92, 1), Decl(lib.d.ts, 223, 11)) +>key : Symbol(key, Decl(sourceMapValidationDecorators.ts, 5, 65)) +>paramIndex : Symbol(paramIndex, Decl(sourceMapValidationDecorators.ts, 5, 87)) @ClassDecorator1 >ClassDecorator1 : Symbol(ClassDecorator1, Decl(sourceMapValidationDecorators.ts, 0, 0)) @@ -49,14 +49,14 @@ declare function ParameterDecorator2(x: number): (target: Function, key: string >ClassDecorator2 : Symbol(ClassDecorator2, Decl(sourceMapValidationDecorators.ts, 0, 57)) class Greeter { ->Greeter : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 118)) +>Greeter : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 116)) constructor( @ParameterDecorator1 >ParameterDecorator1 : Symbol(ParameterDecorator1, Decl(sourceMapValidationDecorators.ts, 3, 128)) @ParameterDecorator2(20) ->ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 103)) +>ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 101)) public greeting: string, >greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) @@ -65,7 +65,7 @@ class Greeter { >ParameterDecorator1 : Symbol(ParameterDecorator1, Decl(sourceMapValidationDecorators.ts, 3, 128)) @ParameterDecorator2(30) ->ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 103)) +>ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 101)) ...b: string[]) { >b : Symbol(b, Decl(sourceMapValidationDecorators.ts, 13, 30)) @@ -82,7 +82,7 @@ class Greeter { return "

" + this.greeting + "

"; >this.greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) ->this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 118)) +>this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 116)) >greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) } @@ -111,14 +111,14 @@ class Greeter { >ParameterDecorator1 : Symbol(ParameterDecorator1, Decl(sourceMapValidationDecorators.ts, 3, 128)) @ParameterDecorator2(70) ->ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 103)) +>ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 101)) x: number) { >x : Symbol(x, Decl(sourceMapValidationDecorators.ts, 34, 15)) return this.greeting; >this.greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) ->this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 118)) +>this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 116)) >greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) } @@ -133,7 +133,7 @@ class Greeter { return this.greeting; >this.greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) ->this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 118)) +>this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 116)) >greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) } @@ -144,14 +144,14 @@ class Greeter { >ParameterDecorator1 : Symbol(ParameterDecorator1, Decl(sourceMapValidationDecorators.ts, 3, 128)) @ParameterDecorator2(90) ->ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 103)) +>ParameterDecorator2 : Symbol(ParameterDecorator2, Decl(sourceMapValidationDecorators.ts, 4, 101)) greetings: string) { >greetings : Symbol(greetings, Decl(sourceMapValidationDecorators.ts, 47, 18)) this.greeting = greetings; >this.greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) ->this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 118)) +>this : Symbol(Greeter, Decl(sourceMapValidationDecorators.ts, 5, 116)) >greeting : Symbol(greeting, Decl(sourceMapValidationDecorators.ts, 10, 16)) >greetings : Symbol(greetings, Decl(sourceMapValidationDecorators.ts, 47, 18)) } diff --git a/tests/baselines/reference/sourceMapValidationDecorators.types b/tests/baselines/reference/sourceMapValidationDecorators.types index 182f68570bc..9e83bb03509 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.types +++ b/tests/baselines/reference/sourceMapValidationDecorators.types @@ -27,18 +27,18 @@ declare function PropertyDecorator2(x: number): (target: Object, key: string | s >descriptor : PropertyDescriptor >PropertyDescriptor : PropertyDescriptor -declare function ParameterDecorator1(target: Function, key: string | symbol, paramIndex: number): void; ->ParameterDecorator1 : (target: Function, key: string | symbol, paramIndex: number) => void ->target : Function ->Function : Function +declare function ParameterDecorator1(target: Object, key: string | symbol, paramIndex: number): void; +>ParameterDecorator1 : (target: Object, key: string | symbol, paramIndex: number) => void +>target : Object +>Object : Object >key : string | symbol >paramIndex : number -declare function ParameterDecorator2(x: number): (target: Function, key: string | symbol, paramIndex: number) => void; ->ParameterDecorator2 : (x: number) => (target: Function, key: string | symbol, paramIndex: number) => void +declare function ParameterDecorator2(x: number): (target: Object, key: string | symbol, paramIndex: number) => void; +>ParameterDecorator2 : (x: number) => (target: Object, key: string | symbol, paramIndex: number) => void >x : number ->target : Function ->Function : Function +>target : Object +>Object : Object >key : string | symbol >paramIndex : number @@ -55,22 +55,22 @@ class Greeter { constructor( @ParameterDecorator1 ->ParameterDecorator1 : (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator1 : (target: Object, key: string | symbol, paramIndex: number) => void @ParameterDecorator2(20) ->ParameterDecorator2(20) : (target: Function, key: string | symbol, paramIndex: number) => void ->ParameterDecorator2 : (x: number) => (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2(20) : (target: Object, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2 : (x: number) => (target: Object, key: string | symbol, paramIndex: number) => void >20 : number public greeting: string, >greeting : string @ParameterDecorator1 ->ParameterDecorator1 : (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator1 : (target: Object, key: string | symbol, paramIndex: number) => void @ParameterDecorator2(30) ->ParameterDecorator2(30) : (target: Function, key: string | symbol, paramIndex: number) => void ->ParameterDecorator2 : (x: number) => (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2(30) : (target: Object, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2 : (x: number) => (target: Object, key: string | symbol, paramIndex: number) => void >30 : number ...b: string[]) { @@ -125,11 +125,11 @@ class Greeter { >fn : (x: number) => string @ParameterDecorator1 ->ParameterDecorator1 : (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator1 : (target: Object, key: string | symbol, paramIndex: number) => void @ParameterDecorator2(70) ->ParameterDecorator2(70) : (target: Function, key: string | symbol, paramIndex: number) => void ->ParameterDecorator2 : (x: number) => (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2(70) : (target: Object, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2 : (x: number) => (target: Object, key: string | symbol, paramIndex: number) => void >70 : number x: number) { @@ -162,11 +162,11 @@ class Greeter { >greetings : string @ParameterDecorator1 ->ParameterDecorator1 : (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator1 : (target: Object, key: string | symbol, paramIndex: number) => void @ParameterDecorator2(90) ->ParameterDecorator2(90) : (target: Function, key: string | symbol, paramIndex: number) => void ->ParameterDecorator2 : (x: number) => (target: Function, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2(90) : (target: Object, key: string | symbol, paramIndex: number) => void +>ParameterDecorator2 : (x: number) => (target: Object, key: string | symbol, paramIndex: number) => void >90 : number greetings: string) { diff --git a/tests/cases/compiler/noEmitHelpers2.ts b/tests/cases/compiler/noEmitHelpers2.ts index df71f4fae82..c794261c65f 100644 --- a/tests/cases/compiler/noEmitHelpers2.ts +++ b/tests/cases/compiler/noEmitHelpers2.ts @@ -2,7 +2,7 @@ // @emitdecoratormetadata: true // @target: es5 -function decorator() { } +declare var decorator: any; @decorator class A { diff --git a/tests/cases/compiler/sourceMapValidationDecorators.ts b/tests/cases/compiler/sourceMapValidationDecorators.ts index c8bd16be80f..f755700197a 100644 --- a/tests/cases/compiler/sourceMapValidationDecorators.ts +++ b/tests/cases/compiler/sourceMapValidationDecorators.ts @@ -4,8 +4,8 @@ declare function ClassDecorator1(target: Function): void; declare function ClassDecorator2(x: number): (target: Function) => void; declare function PropertyDecorator1(target: Object, key: string | symbol, descriptor?: PropertyDescriptor): void; declare function PropertyDecorator2(x: number): (target: Object, key: string | symbol, descriptor?: PropertyDescriptor) => void; -declare function ParameterDecorator1(target: Function, key: string | symbol, paramIndex: number): void; -declare function ParameterDecorator2(x: number): (target: Function, key: string | symbol, paramIndex: number) => void; +declare function ParameterDecorator1(target: Object, key: string | symbol, paramIndex: number): void; +declare function ParameterDecorator2(x: number): (target: Object, key: string | symbol, paramIndex: number) => void; @ClassDecorator1 @ClassDecorator2(10) diff --git a/tests/cases/conformance/decorators/class/decoratedClassFromExternalModule.ts b/tests/cases/conformance/decorators/class/decoratedClassFromExternalModule.ts index cb622265b44..979bb28965a 100644 --- a/tests/cases/conformance/decorators/class/decoratedClassFromExternalModule.ts +++ b/tests/cases/conformance/decorators/class/decoratedClassFromExternalModule.ts @@ -1,6 +1,6 @@ // @target: es6 // @Filename: decorated.ts -function decorate() { } +function decorate(target: any) { } @decorate export default class Decorated { } diff --git a/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts b/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts index 31f5fe82551..8a9cb6a7ecf 100644 --- a/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts +++ b/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts @@ -5,7 +5,7 @@ function func(s: string): void { } class A { - @(x => { + @((x, p) => { var a = 3; func(a); return x; diff --git a/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts b/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts index 7fa7ab8dd84..ce153d2fef0 100644 --- a/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts +++ b/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts @@ -9,7 +9,7 @@ export var test = 'abc'; import { test } from './a'; function filter(handler: any) { - return function (target: any) { + return function (target: any, propertyKey: string) { // ... }; } diff --git a/tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts b/tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts index df0b847e99d..f506af5d841 100644 --- a/tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts +++ b/tests/cases/conformance/decorators/class/method/decoratorOnClassMethod13.ts @@ -1,5 +1,5 @@ // @target: ES6 -declare function dec(): (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor; +declare function dec(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; class C { @dec ["1"]() { } diff --git a/tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts b/tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts index e525933fb6a..fa9c85c6f8e 100644 --- a/tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts +++ b/tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter1.ts @@ -1,5 +1,5 @@ // @target:es5 -declare function dec(target: Function, propertyKey: string | symbol, parameterIndex: number): void; +declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void; class C { method(@dec p: number) {} diff --git a/tests/cases/conformance/decorators/missingDecoratorType.ts b/tests/cases/conformance/decorators/missingDecoratorType.ts index 1407e00b7a3..286595d450e 100644 --- a/tests/cases/conformance/decorators/missingDecoratorType.ts +++ b/tests/cases/conformance/decorators/missingDecoratorType.ts @@ -1,4 +1,4 @@ -// @target: ES5 +// @target: ES5 // @noLib: true // @Filename: a.ts @@ -11,11 +11,12 @@ interface Function { } interface RegExp { } interface IArguments { } -// @Filename: b.ts +// @Filename: b.ts /// -declare var dec: any; +declare function dec(t, k, d); -@dec class C { + @dec + method() {} } From 666a0db6ae646e2f0eba192055ad6c70269dac13 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 22 May 2015 23:56:41 -0700 Subject: [PATCH 2/5] PR Feedback --- src/compiler/checker.ts | 279 ++++++++++-------- .../diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/utilities.ts | 7 +- .../reference/decoratorOnClass8.errors.txt | 4 +- .../decoratorOnClassMethod10.errors.txt | 4 +- .../decoratorOnClassMethod6.errors.txt | 4 +- .../decoratorOnClassMethod8.errors.txt | 4 +- .../decoratorOnClassProperty11.errors.txt | 4 +- .../decoratorOnClassProperty6.errors.txt | 4 +- .../decoratorOnClassProperty7.errors.txt | 4 +- 11 files changed, 174 insertions(+), 144 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e99dd7eeb4e..6cd98c43529 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6774,13 +6774,29 @@ module ts { let arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { let paramType = getTypeAtPosition(signature, i); - let argType = getSyntheticArgumentType(i, arg); + let argType: Type; + if (arg.parent.kind === SyntaxKind.Decorator) { + if (i === 0) { + argType = getDecoratorTargetArgumentType(arg.parent.parent); + } + else if (i === 1) { + argType = getDecoratorPropertyKeyArgumentType(arg.parent.parent); + } + else if (i === 2) { + argType = getDecoratorPropertyIndexOrDescriptorArgumentType(arg.parent.parent); + } + } + else if (i === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { + argType = globalTemplateStringsArrayType; + } + if (argType === undefined) { // For context sensitive arguments we pass the identityMapper, which is a signal to treat all // context sensitive function expressions as wildcards let mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; argType = checkExpressionWithContextualType(arg, paramType, mapper); } + inferTypes(context, argType, paramType); } } @@ -6838,140 +6854,151 @@ module ts { : emptyObjectType; } - /** - * Gets the type for a synthetic argument when resolving the first argument for a TaggedTemplateExpression - * or any arguments to a Decorator. - */ - function getSyntheticArgumentType(argumentIndex: number, arg: Expression): Type { - if (arg.parent.kind === SyntaxKind.Decorator) { - let decorator = arg.parent; - let parent = decorator.parent; - if (argumentIndex === 0) { - // The first argument to a decorator is its `target`. - switch (parent.kind) { - case SyntaxKind.ClassDeclaration: - // For a class decorator, the `target` is the type of the class (e.g. the - // "static" or "constructor" side of the class) - let classSymbol = getSymbolOfNode(parent); - return getTypeOfSymbol(classSymbol); - - case SyntaxKind.Parameter: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. - parent = parent.parent; - if (parent.kind === SyntaxKind.Constructor) { - let classSymbol = getSymbolOfNode(parent); - return getTypeOfSymbol(classSymbol); - } - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // For a property or method decorator, the `target` is the - // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the - // parent of the member. - return getTypeOfParentOfClassElement(parent); + function getDecoratorTargetArgumentType(target: Node): Type { + // The first argument to a decorator is its `target`. + switch (target.kind) { + case SyntaxKind.ClassDeclaration: + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + let classSymbol = getSymbolOfNode(target); + return getTypeOfSymbol(classSymbol); + + case SyntaxKind.Parameter: + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + target = target.parent; + if (target.kind === SyntaxKind.Constructor) { + let classSymbol = getSymbolOfNode(target); + return getTypeOfSymbol(classSymbol); } - } - else if (argumentIndex === 1) { - // The second argument to a decorator is its `propertyKey` - switch (parent.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a second synthetic argument."); - - case SyntaxKind.Parameter: - parent = parent.parent; - if (parent.kind === SyntaxKind.Constructor) { - // For a constructor parameter decorator, the `propertyKey` will be `undefined`. - return anyType; - } - - // For a non-constructor parameter decorator, the `propertyKey` will be either - // a string or a symbol, based on the name of the parameter's containing method. - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; - // otherwise, if the member name is a computed property name it will - // be either string or symbol. - let element = decorator.parent; - switch (element.name.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.NumericLiteral: - case SyntaxKind.StringLiteral: - return getStringLiteralType(element.name); - - case SyntaxKind.ComputedPropertyName: - let nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { - return nameType; - } - else { - return stringType; - } - } - } - } - else if (argumentIndex === 2) { - // The third argument to a decorator is either its `descriptor` for a method decorator - // or its `parameterIndex` for a paramter decorator - switch (parent.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a third synthetic argument."); - break; - - case SyntaxKind.Parameter: - // The `parameterIndex` for a parameter decorator is always a number - return numberType; - - case SyntaxKind.PropertyDeclaration: - Debug.fail("Property decorators should not have a third synthetic argument."); - break; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` - // for the type of the member. - let propertyType: Type = getTypeOfNode(parent); - return createTypedPropertyDescriptorType(propertyType); - } - } + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getTypeOfParentOfClassElement(target); + + default: + return undefined; } - else if (argumentIndex === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { - return globalTemplateStringsArrayType; - } - - return undefined; } + + function getDecoratorPropertyKeyArgumentType(target: Node) { + // The second argument to a decorator is its `propertyKey` + switch (target.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a second synthetic argument."); + + case SyntaxKind.Parameter: + target = target.parent; + if (target.kind === SyntaxKind.Constructor) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } + + // For a non-constructor parameter decorator, the `propertyKey` will be either + // a string or a symbol, based on the name of the parameter's containing method. + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + let element = target; + switch (element.name.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + return getStringLiteralType(element.name); + + case SyntaxKind.ComputedPropertyName: + let nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { + return nameType; + } + else { + return stringType; + } + } + } + } + + function getDecoratorPropertyIndexOrDescriptorArgumentType(parent: Node) { + // The third argument to a decorator is either its `descriptor` for a method decorator + // or its `parameterIndex` for a paramter decorator + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a third synthetic argument."); + break; + case SyntaxKind.Parameter: + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + + case SyntaxKind.PropertyDeclaration: + Debug.fail("Property decorators should not have a third synthetic argument."); + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + let propertyType: Type = getTypeOfNode(parent); + return createTypedPropertyDescriptorType(propertyType); + } + } + function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean, containingMessageChain?: DiagnosticMessageChain) { for (let i = 0; i < args.length; i++) { let arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter) let paramType = getTypeAtPosition(signature, i); - // A tagged template expression provides a special first argument, and string literals get string literal types + + // Decorators provide special arguments, a tagged template expression provides + // a special first argument, and string literals get string literal types // unless we're reporting errors - let argType = getSyntheticArgumentType(i, arg); + let argType: Type; + if (arg.parent.kind === SyntaxKind.Decorator) { + if (i === 0) { + argType = getDecoratorTargetArgumentType(arg.parent.parent); + } + else if (i === 1) { + argType = getDecoratorPropertyKeyArgumentType(arg.parent.parent); + } + else if (i === 2) { + argType = getDecoratorPropertyIndexOrDescriptorArgumentType(arg.parent.parent); + } + } + else if (i === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { + argType = globalTemplateStringsArrayType; + } + if (argType === undefined) { - argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors - ? getStringLiteralType(arg) - : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + if (arg.kind === SyntaxKind.StringLiteral && !reportErrors) { + argType = getStringLiteralType(arg); + } + else { + argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + } } // Use argument expression as error location when reporting errors - if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1, containingMessageChain)) { + let errorNode = reportErrors ? arg : undefined; + let headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; + if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage, containingMessageChain)) { return false; } } @@ -6986,7 +7013,8 @@ module ts { * If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution * expressions, where the first element of the list is the template for error reporting purposes. * If 'node' is a Decorator, a new argument list is constructed with the decorator - * expression as a placeholder. + * expression as a placeholder to help when choosing an applicable signature and + * for error reporting purposes. */ function getEffectiveCallArguments(node: CallLikeExpression): Expression[] { let args: Expression[]; @@ -7082,6 +7110,9 @@ module ts { // // For a tagged template, then the first argument be 'undefined' if necessary // because it represents a TemplateStringsArray. + // + // 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. let excludeArgument: boolean[]; if (!isDecorator) { for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { @@ -7441,7 +7472,9 @@ module ts { break; } - let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Invalid_expression_for_0_decorator, decoratorKind); + let diagnosticChainHead = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression, decoratorKind); if (!callSignatures.length) { let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); errorInfo = concatenateDiagnosticMessageChains(diagnosticChainHead, errorInfo); @@ -9140,7 +9173,7 @@ module ts { diagnosticChainHead = chainDiagnosticMessages( diagnosticChainHead, - Diagnostics.Invalid_expression_for_0_decorator, + Diagnostics.Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression, decoratorKind); checkTypeAssignableTo(returnType, expectedReturnType, node, /*headMessage*/ undefined, diagnosticChainHead); diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 1eaf69d8886..a1b776611f7 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -175,7 +175,7 @@ module ts { Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, Export_assignment_is_not_supported_when_module_flag_is_system: { code: 1218, category: DiagnosticCategory.Error, key: "Export assignment is not supported when '--module' flag is 'system'." }, The_return_type_of_a_0_decorator_function_must_be_either_void_or_any: { code: 1219, category: DiagnosticCategory.Error, key: "The return type of a {0} decorator function must be either 'void' or 'any'." }, - Invalid_expression_for_0_decorator: { code: 1220, category: DiagnosticCategory.Error, key: "Invalid expression for {0} decorator." }, + Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression: { code: 1220, category: DiagnosticCategory.Error, key: "Unable to resolve signature of {0} decorator when called as an expression." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 36f7505fc65..27238db5d95 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -687,7 +687,7 @@ "category": "Error", "code": 1219 }, - "Invalid expression for {0} decorator.": { + "Unable to resolve signature of {0} decorator when called as an expression.": { "category": "Error", "code": 1220 }, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e720c7a112e..f1239b87629 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -620,12 +620,9 @@ module ts { if (node.kind === SyntaxKind.TaggedTemplateExpression) { return (node).tag; } - else if (node.kind === SyntaxKind.Decorator) { - return (node).expression; - } - // Will either be a CallExpression or NewExpression. - return (node).expression; + // Will either be a CallExpression, NewExpression, or Decorator. + return (node).expression; } export function nodeCanBeDecorated(node: Node): boolean { diff --git a/tests/baselines/reference/decoratorOnClass8.errors.txt b/tests/baselines/reference/decoratorOnClass8.errors.txt index 31abd9e2300..b5e27b4b3cb 100644 --- a/tests/baselines/reference/decoratorOnClass8.errors.txt +++ b/tests/baselines/reference/decoratorOnClass8.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220: Invalid expression for class decorator. +tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220: Unable to resolve signature of class decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -7,7 +7,7 @@ tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220 @dec() ~~~~~~ -!!! error TS1220: Invalid expression for class decorator. +!!! error TS1220: Unable to resolve signature of class decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. class C { } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt index bfc56717e6c..1d94f08f2a2 100644 --- a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6): error TS1220: Invalid expression for method decorator. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6): error TS1220: Unable to resolve signature of method decorator when called as an expression. Argument of type 'C' is not assignable to parameter of type 'Function'. Property 'apply' is missing in type 'C'. @@ -9,7 +9,7 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6) class C { @dec method() {} ~~~ -!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. !!! error TS1220: Argument of type 'C' is not assignable to parameter of type 'Function'. !!! error TS1220: Property 'apply' is missing in type 'C'. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod6.errors.txt b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt index ade416aefbc..2231d0da56d 100644 --- a/tests/baselines/reference/decoratorOnClassMethod6.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1220: Invalid expression for method decorator. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1220: Unable to resolve signature of method decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): class C { @dec ["method"]() {} ~~~~ -!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod8.errors.txt b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt index d0635b4f5f3..d80fe7e05f7 100644 --- a/tests/baselines/reference/decoratorOnClassMethod8.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): error TS1220: Invalid expression for method decorator. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): error TS1220: Unable to resolve signature of method decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): class C { @dec method() {} ~~~~ -!!! error TS1220: Invalid expression for method decorator. +!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty11.errors.txt b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt index 92b89b0b430..8dad5dc955f 100644 --- a/tests/baselines/reference/decoratorOnClassProperty11.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1220: Invalid expression for property decorator. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts( class C { @dec prop; ~~~~ -!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt index 441ff38a421..eca97e803e0 100644 --- a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4,5): error TS1220: Invalid expression for property decorator. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4 class C { @dec prop; ~~~~ -!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt index e061ce446ac..7f2249e5934 100644 --- a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS1220: Invalid expression for property decorator. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4 class C { @dec prop; ~~~~ -!!! error TS1220: Invalid expression for property decorator. +!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. !!! error TS1220: Supplied parameters do not match any signature of call target. } \ No newline at end of file From f559d061eceefe539c117f544dba254c7a98731e Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 27 May 2015 10:19:37 -0700 Subject: [PATCH 3/5] PR feedback and minor refactoring --- src/compiler/checker.ts | 714 ++++++++++-------- .../diagnosticInformationMap.generated.ts | 8 +- src/compiler/diagnosticMessages.json | 21 +- .../reference/decoratorOnClass8.errors.txt | 6 +- .../decoratorOnClassMethod10.errors.txt | 10 +- .../decoratorOnClassMethod6.errors.txt | 6 +- .../decoratorOnClassMethod8.errors.txt | 6 +- .../decoratorOnClassProperty11.errors.txt | 6 +- .../decoratorOnClassProperty6.errors.txt | 6 +- .../decoratorOnClassProperty7.errors.txt | 6 +- 10 files changed, 455 insertions(+), 334 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6cd98c43529..57e1f8190f0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3504,6 +3504,16 @@ module ts { return globalESSymbolConstructorSymbol || (globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol")); } + /** + * Creates a TypeReference for a generic `TypedPropertyDescriptor`. + */ + function createTypedPropertyDescriptorType(propertyType: Type): Type { + let globalTypedPropertyDescriptorType = getGlobalTypedPropertyDescriptorType(); + return globalTypedPropertyDescriptorType !== emptyObjectType + ? createTypeReference(globalTypedPropertyDescriptorType, [propertyType]) + : emptyObjectType; + } + function createIterableType(elementType: Type): Type { return globalIterableType !== emptyObjectType ? createTypeReference(globalIterableType, [elementType]) : emptyObjectType; } @@ -6605,7 +6615,8 @@ module ts { function getSpreadArgumentIndex(args: Expression[]): number { for (let i = 0; i < args.length; i++) { - if (args[i].kind === SyntaxKind.SpreadElementExpression) { + let arg = args[i]; + if (arg && arg.kind === SyntaxKind.SpreadElementExpression) { return i; } } @@ -6616,7 +6627,8 @@ module ts { let adjustedArgCount: number; // Apparent number of arguments we will have in this call let typeArguments: NodeArray; // Type arguments (undefined if none) let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments - + let isDecorator: boolean; + if (node.kind === SyntaxKind.TaggedTemplateExpression) { let tagExpression = node; @@ -6643,39 +6655,9 @@ module ts { } } else if (node.kind === SyntaxKind.Decorator) { - let decorator = node; - switch (decorator.parent.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - // A class decorator will have one argument (see `ClassDecorator` in core.d.ts) - adjustedArgCount = 1; - typeArguments = undefined; - break; - - case SyntaxKind.PropertyDeclaration: - // A property declaration decorator will have two arguments (see - // `PropertyDecorator` in core.d.ts) - adjustedArgCount = 2; - typeArguments = undefined; - break; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // A method or accessor declaration decorator will have two or three arguments (see - // `MethodDecorator` in core.d.ts) - adjustedArgCount = signature.parameters.length >= 3 ? 3 : 2; - typeArguments = undefined; - break; - - case SyntaxKind.Parameter: - // A parameter declaration decorator will have three arguments (see - // `ParameterDecorator` in core.d.ts) - - adjustedArgCount = 3; - typeArguments = undefined; - break; - } + isDecorator = true; + typeArguments = undefined; + adjustedArgCount = getEffectiveArgumentCount(node, /*args*/ undefined, signature); } else { let callExpression = node; @@ -6705,7 +6687,7 @@ module ts { // If spread arguments are present, check that they correspond to a rest parameter. If so, no // further checking is necessary. - let spreadArgIndex = getSpreadArgumentIndex(args); + let spreadArgIndex = !isDecorator ? getSpreadArgumentIndex(args) : -1; if (spreadArgIndex >= 0) { return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1; } @@ -6742,7 +6724,7 @@ module ts { return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { + function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { let typeParameters = signature.typeParameters; let inferenceMapper = createInferenceMapper(context); @@ -6770,33 +6752,12 @@ module ts { // We perform two passes over the arguments. In the first pass we infer from all arguments, but use // wildcards for all context sensitive function expressions. - for (let i = 0; i < args.length; i++) { - let arg = args[i]; - if (arg.kind !== SyntaxKind.OmittedExpression) { + let argCount = getEffectiveArgumentCount(node, args, signature); + for (let i = 0; i < argCount; i++) { + let arg = getEffectiveArgument(node, args, i); + if (!arg || arg.kind !== SyntaxKind.OmittedExpression) { let paramType = getTypeAtPosition(signature, i); - let argType: Type; - if (arg.parent.kind === SyntaxKind.Decorator) { - if (i === 0) { - argType = getDecoratorTargetArgumentType(arg.parent.parent); - } - else if (i === 1) { - argType = getDecoratorPropertyKeyArgumentType(arg.parent.parent); - } - else if (i === 2) { - argType = getDecoratorPropertyIndexOrDescriptorArgumentType(arg.parent.parent); - } - } - else if (i === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { - argType = globalTemplateStringsArrayType; - } - - if (argType === undefined) { - // For context sensitive arguments we pass the identityMapper, which is a signal to treat all - // context sensitive function expressions as wildcards - let mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; - argType = checkExpressionWithContextualType(arg, paramType, mapper); - } - + let argType = getEffectiveArgumentType(node, i, arg, paramType, excludeArgument, inferenceMapper, /*reportErrors*/ false); inferTypes(context, argType, paramType); } } @@ -6804,8 +6765,10 @@ module ts { // In the second pass we visit only context sensitive arguments, and only those that aren't excluded, this // time treating function expressions normally (which may cause previously inferred type arguments to be fixed // as we construct types for contextually typed parameters) + // Decorators will not have `excludeArgument`, as their arguments cannot be contextually typed. + // Tagged template expressions will always have `undefined` for `excludeArgument[0]`. if (excludeArgument) { - for (let i = 0; i < args.length; i++) { + for (let i = 0; i < argCount; i++) { // No need to check for omitted args and template expressions, their exlusion value is always undefined if (excludeArgument[i] === false) { let arg = args[i]; @@ -6818,7 +6781,7 @@ module ts { getInferredTypes(context); } - function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean, containingMessageChain?: DiagnosticMessageChain): boolean { + function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): boolean { let typeParameters = signature.typeParameters; let typeArgumentsAreAssignable = true; for (let i = 0; i < typeParameters.length; i++) { @@ -6829,180 +6792,44 @@ module ts { if (typeArgumentsAreAssignable /* so far */) { let constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { - typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined, - Diagnostics.Type_0_does_not_satisfy_the_constraint_1, containingMessageChain); + let errorInfo: DiagnosticMessageChain; + let typeArgumentHeadMessage = Diagnostics.Type_0_does_not_satisfy_the_constraint_1; + if (reportErrors && headMessage) { + errorInfo = chainDiagnosticMessages(errorInfo, typeArgumentHeadMessage); + typeArgumentHeadMessage = headMessage; + } + + typeArgumentsAreAssignable = checkTypeAssignableTo( + typeArgument, + constraint, + reportErrors ? typeArgNode : undefined, + typeArgumentHeadMessage, + errorInfo); } } } + return typeArgumentsAreAssignable; } - - function getTypeOfParentOfClassElement(node: ClassElement) { - let classSymbol = getSymbolOfNode(node.parent); - if (node.flags & NodeFlags.Static) { - return getTypeOfSymbol(classSymbol); - } - else { - return getDeclaredTypeOfSymbol(classSymbol); - } - } - - function createTypedPropertyDescriptorType(propertyType: Type): Type { - let globalTypedPropertyDescriptorType = getGlobalTypedPropertyDescriptorType(); - return globalTypedPropertyDescriptorType !== emptyObjectType - ? createTypeReference(globalTypedPropertyDescriptorType, [propertyType]) - : emptyObjectType; - } - - function getDecoratorTargetArgumentType(target: Node): Type { - // The first argument to a decorator is its `target`. - switch (target.kind) { - case SyntaxKind.ClassDeclaration: - // For a class decorator, the `target` is the type of the class (e.g. the - // "static" or "constructor" side of the class) - let classSymbol = getSymbolOfNode(target); - return getTypeOfSymbol(classSymbol); - - case SyntaxKind.Parameter: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. - target = target.parent; - if (target.kind === SyntaxKind.Constructor) { - let classSymbol = getSymbolOfNode(target); - return getTypeOfSymbol(classSymbol); - } - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // For a property or method decorator, the `target` is the - // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the - // parent of the member. - return getTypeOfParentOfClassElement(target); - - default: - return undefined; - } - } - - function getDecoratorPropertyKeyArgumentType(target: Node) { - // The second argument to a decorator is its `propertyKey` - switch (target.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a second synthetic argument."); - - case SyntaxKind.Parameter: - target = target.parent; - if (target.kind === SyntaxKind.Constructor) { - // For a constructor parameter decorator, the `propertyKey` will be `undefined`. - return anyType; - } - - // For a non-constructor parameter decorator, the `propertyKey` will be either - // a string or a symbol, based on the name of the parameter's containing method. - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; - // otherwise, if the member name is a computed property name it will - // be either string or symbol. - let element = target; - switch (element.name.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.NumericLiteral: - case SyntaxKind.StringLiteral: - return getStringLiteralType(element.name); - - case SyntaxKind.ComputedPropertyName: - let nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { - return nameType; - } - else { - return stringType; - } - } - } - } - - function getDecoratorPropertyIndexOrDescriptorArgumentType(parent: Node) { - // The third argument to a decorator is either its `descriptor` for a method decorator - // or its `parameterIndex` for a paramter decorator - switch (parent.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a third synthetic argument."); - break; - case SyntaxKind.Parameter: - // The `parameterIndex` for a parameter decorator is always a number - return numberType; - - case SyntaxKind.PropertyDeclaration: - Debug.fail("Property decorators should not have a third synthetic argument."); - break; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` - // for the type of the member. - let propertyType: Type = getTypeOfNode(parent); - return createTypedPropertyDescriptorType(propertyType); - } - } - - function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean, containingMessageChain?: DiagnosticMessageChain) { - for (let i = 0; i < args.length; i++) { - let arg = args[i]; - if (arg.kind !== SyntaxKind.OmittedExpression) { + function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) { + let argCount = getEffectiveArgumentCount(node, args, signature); + for (let i = 0; i < argCount; i++) { + let arg = getEffectiveArgument(node, args, i); + if (!arg || arg.kind !== SyntaxKind.OmittedExpression) { // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter) let paramType = getTypeAtPosition(signature, i); - - // Decorators provide special arguments, a tagged template expression provides - // a special first argument, and string literals get string literal types - // unless we're reporting errors - let argType: Type; - if (arg.parent.kind === SyntaxKind.Decorator) { - if (i === 0) { - argType = getDecoratorTargetArgumentType(arg.parent.parent); - } - else if (i === 1) { - argType = getDecoratorPropertyKeyArgumentType(arg.parent.parent); - } - else if (i === 2) { - argType = getDecoratorPropertyIndexOrDescriptorArgumentType(arg.parent.parent); - } - } - else if (i === 0 && arg.parent.kind === SyntaxKind.TaggedTemplateExpression) { - argType = globalTemplateStringsArrayType; - } - - if (argType === undefined) { - if (arg.kind === SyntaxKind.StringLiteral && !reportErrors) { - argType = getStringLiteralType(arg); - } - else { - argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); - } - } + let argType = getEffectiveArgumentType(node, i, arg, paramType, excludeArgument, /*inferenceMapper*/ undefined, reportErrors); // Use argument expression as error location when reporting errors - let errorNode = reportErrors ? arg : undefined; + let errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined; let headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1; - if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage, containingMessageChain)) { + if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage)) { return false; } } } + return true; } @@ -7011,17 +6838,15 @@ module ts { * * If 'node' is a CallExpression or a NewExpression, then its argument list is returned. * If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution - * expressions, where the first element of the list is the template for error reporting purposes. - * If 'node' is a Decorator, a new argument list is constructed with the decorator - * expression as a placeholder to help when choosing an applicable signature and - * for error reporting purposes. + * expressions, where the first element of the list is `undefined`. + * If 'node' is a Decorator, the argument list will be `undefined`, and its arguments and types + * will be supplied from calls to `getEffectiveArgumentCount` and `getEffectiveArgumentType`. */ function getEffectiveCallArguments(node: CallLikeExpression): Expression[] { let args: Expression[]; if (node.kind === SyntaxKind.TaggedTemplateExpression) { let template = (node).template; - args = [template]; - + args = [undefined]; if (template.kind === SyntaxKind.TemplateExpression) { forEach((template).templateSpans, span => { args.push(span.expression); @@ -7029,21 +6854,10 @@ module ts { } } else if (node.kind === SyntaxKind.Decorator) { - let decorator = node; - switch (decorator.parent.kind) { - case SyntaxKind.ClassDeclaration: - args = [decorator.expression]; - break; - case SyntaxKind.PropertyDeclaration: - args = [decorator.expression, decorator.expression]; - break; - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Parameter: - args = [decorator.expression, decorator.expression, decorator.expression]; - break; - } + // For a decorator, we return undefined as we will determine + // the number and types of arguments for a decorator using + // `getEffectiveArgumentCount` and `getEffectiveArgumentType` below. + return undefined; } else { args = (node).arguments || emptyArray; @@ -7074,7 +6888,287 @@ module ts { } } - function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], containingMessageChain?: DiagnosticMessageChain): Signature { + /** + * Returns the effective argument count for a node that works like a function invocation. + * If 'node' is a Decorator, the number of arguments is derived from the decoration + * target and the signature: + * If 'node.target' is a class declaration or class expression, the effective argument + * count is 1. + * If 'node.target' is a parameter declaration, the effective argument count is 3. + * If 'node.target' is a property declaration, the effective argument count is 2. + * If 'node.target' is a method or accessor declaration, the effective argument count + * is 3, although it can be 2 if the signature only accepts two arguments, allowing + * us to match a property decorator. + * Otherwise, the argument count is the length of the 'args' array. + */ + function getEffectiveArgumentCount(node: CallLikeExpression, args: Expression[], signature: Signature) { + if (node.kind === SyntaxKind.Decorator) { + switch (node.parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + // A class decorator will have one argument (see `ClassDecorator` in core.d.ts) + return 1; + + case SyntaxKind.PropertyDeclaration: + // A property declaration decorator will have two arguments (see + // `PropertyDecorator` in core.d.ts) + return 2; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // A method or accessor declaration decorator will have two or three arguments (see + // `PropertyDecorator` and `MethodDecorator` in core.d.ts) + // If the method decorator signature only accepts a target and a key, we will only + // type check those arguments. + return signature.parameters.length >= 3 ? 3 : 2; + + case SyntaxKind.Parameter: + // A parameter declaration decorator will have three arguments (see + // `ParameterDecorator` in core.d.ts) + + return 3; + } + } + else { + return args.length; + } + } + + /** + * Returns the effective type of the first argument to a decorator. + * If 'node' is a class declaration or class expression, the effective argument type + * is the type of the static side of the class. + * If 'node' is a parameter declaration, the effective argument type is either the type + * of the static or instance side of the class for the parameter's parent method, + * depending on whether the method is declared static. + * For a constructor, the type is always the type of the static side of the class. + * If 'node' is a property, method, or accessor declaration, the effective argument + * type is the type of the static or instance side of the parent class for class + * element, depending on whether the element is declared static. + */ + function getEffectiveDecoratorFirstArgumentType(node: Node): Type { + // The first argument to a decorator is its `target`. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + let classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + + case SyntaxKind.Parameter: + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + node = node.parent; + if (node.kind === SyntaxKind.Constructor) { + let classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getParentTypeOfClassElement(node); + + default: + Debug.fail("Unsupported decorator target."); + return unknownType; + } + } + + /** + * Returns the effective type for the second argument to a decorator. + * If 'node' is a parameter, its effective argument type is one of the following: + * If 'node.parent' is a constructor, the effective argument type is 'any', as we + * will emit `undefined`. + * If 'node.parent' is a member with an identifier, numeric, or string literal name, + * the effective argument type will be a string literal type for the member name. + * If 'node.parent' is a computed property name, the effective argument type will + * either be a symbol type or the string type. + * If 'node' is a member with an identifier, numeric, or string literal name, the + * effective argument type will be a string literal type for the member name. + * If 'node' is a computed property name, the effective argument type will either + * be a symbol type or the string type. + * A class decorator does not have a second argument type. + */ + function getEffectiveDecoratorSecondArgumentType(node: Node) { + // The second argument to a decorator is its `propertyKey` + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; + + case SyntaxKind.Parameter: + node = node.parent; + if (node.kind === SyntaxKind.Constructor) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } + + // For a non-constructor parameter decorator, the `propertyKey` will be either + // a string or a symbol, based on the name of the parameter's containing method. + + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + let element = node; + switch (element.name.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + return getStringLiteralType(element.name); + + case SyntaxKind.ComputedPropertyName: + let nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { + return nameType; + } + else { + return stringType; + } + + default: + Debug.fail("Unsupported property name."); + return unknownType; + } + + + default: + Debug.fail("Unsupported decorator target."); + return unknownType; + } + } + + /** + * Returns the effective argument type for the third argument to a decorator. + * If 'node' is a parameter, the effective argument type is the number type. + * If 'node' is a method or accessor, the effective argument type is a + * `TypedPropertyDescriptor` instantiated with the type of the member. + * Class and property decorators do not have a third effective argument. + */ + function getEffectiveDecoratorThirdArgumentType(node: Node) { + // The third argument to a decorator is either its `descriptor` for a method decorator + // or its `parameterIndex` for a paramter decorator + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; + + case SyntaxKind.Parameter: + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + + case SyntaxKind.PropertyDeclaration: + Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + let propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + + default: + Debug.fail("Unsupported decorator target."); + return unknownType; + } + } + + /** + * Returns the effective argument type for the provided argument to a decorator. + */ + function getEffectiveDecoratorArgumentType(node: Decorator, argIndex: number): Type { + if (argIndex === 0) { + return getEffectiveDecoratorFirstArgumentType(node.parent); + } + else if (argIndex === 1) { + return getEffectiveDecoratorSecondArgumentType(node.parent); + } + else if (argIndex === 2) { + return getEffectiveDecoratorThirdArgumentType(node.parent); + } + + Debug.fail("Decorators should not have a fourth synthetic argument."); + return unknownType; + } + + /** + * Gets the effective argument type for an argument in a call expression. + */ + function getEffectiveArgumentType(node: CallLikeExpression, argIndex: number, arg: Expression, paramType: Type, excludeArgument: boolean[], inferenceMapper: TypeMapper, reportErrors: boolean): Type { + // Decorators provide special arguments, a tagged template expression provides + // a special first argument, and string literals get string literal types + // unless we're reporting errors + if (node.kind === SyntaxKind.Decorator) { + return getEffectiveDecoratorArgumentType(node, argIndex); + } + else if (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) { + return globalTemplateStringsArrayType; + } + else if (!inferenceMapper && !reportErrors && arg.kind === SyntaxKind.StringLiteral) { + return getStringLiteralType(arg); + } + else { + let mapper: TypeMapper; + if (inferenceMapper) { + mapper = excludeArgument && excludeArgument[argIndex] !== undefined ? identityMapper : inferenceMapper; + } + else { + mapper = excludeArgument && excludeArgument[argIndex] ? identityMapper : undefined; + } + + return checkExpressionWithContextualType(arg, paramType, mapper); + } + } + + /** + * Gets the effective argument expression for an argument in a call expression. + */ + function getEffectiveArgument(node: CallLikeExpression, args: Expression[], argIndex: number) { + // For a decorator or the first argument of a tagged template expression we return undefined. + if (node.kind === SyntaxKind.Decorator || + (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression)) { + return undefined; + } + + return args[argIndex]; + } + + /** + * Gets the error node to use when reporting errors for an effective argument. + */ + function getEffectiveArgumentErrorNode(node: CallLikeExpression, argIndex: number, arg: Expression) { + if (node.kind === SyntaxKind.Decorator) { + // For a decorator, we use the expression of the decorator for error reporting. + return (node).expression; + } + else if (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) { + // For a the first argument of a tagged template expression, we use the template of the tag for error reporting. + return (node).template; + } + else { + return arg; + } + } + + function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], headMessage?: DiagnosticMessage): Signature { let isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; let isDecorator = node.kind === SyntaxKind.Decorator; @@ -7115,6 +7209,8 @@ module ts { // decorators are applied to a declaration by the emitter, and not to an expression. let excludeArgument: boolean[]; if (!isDecorator) { + // We do not need to call `getEffectiveArgumentCount` here as it only + // applies when calculating the number of arguments for a decorator. for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { if (isContextSensitive(args[i])) { if (!excludeArgument) { @@ -7185,11 +7281,11 @@ module ts { // in arguments too early. If possible, we'd like to only type them once we know the correct // overload. However, this matters for the case where the call is correct. When the call is // an error, we don't need to exclude any arguments, although it would cause no harm to do so. - checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true, containingMessageChain); + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true); } else if (candidateForTypeArgumentError) { if (!isTaggedTemplate && !isDecorator && (node).typeArguments) { - checkTypeArguments(candidateForTypeArgumentError, (node).typeArguments, [], /*reportErrors*/ true, containingMessageChain) + checkTypeArguments(candidateForTypeArgumentError, (node).typeArguments, [], /*reportErrors*/ true, headMessage) } else { Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); @@ -7200,8 +7296,8 @@ module ts { Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly, typeToString(failedTypeParameter)); - if (containingMessageChain) { - diagnosticChainHead = concatenateDiagnosticMessageChains(containingMessageChain, diagnosticChainHead); + if (headMessage) { + diagnosticChainHead = chainDiagnosticMessages(diagnosticChainHead, headMessage); } reportNoCommonSupertypeError(inferenceCandidates, (node).expression || (node).tag, diagnosticChainHead); @@ -7227,9 +7323,10 @@ module ts { return resolveErrorCall(node); function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void { - let errorInfo = chainDiagnosticMessages(/*details*/ undefined, message, arg0, arg1, arg2); - if (containingMessageChain) { - errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo); + let errorInfo: DiagnosticMessageChain; + errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2); + if (headMessage) { + errorInfo = chainDiagnosticMessages(errorInfo, headMessage); } diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo)); @@ -7256,7 +7353,7 @@ module ts { typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false) } else { - inferTypeArguments(candidate, args, excludeArgument, inferenceContext); + inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined; typeArgumentTypes = inferenceContext.inferredTypes; } @@ -7433,7 +7530,32 @@ module ts { return resolveCall(node, callSignatures, candidatesOutArray); } + + /** + * Gets the localized diagnostic head message to use for errors when resolving a decorator as a call expression. + */ + function getDiagnosticHeadMessageForDecoratorResolution(node: Decorator) { + switch (node.parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return Diagnostics.Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression; + + case SyntaxKind.Parameter: + return Diagnostics.Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression; + + case SyntaxKind.PropertyDeclaration: + return Diagnostics.Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return Diagnostics.Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression; + } + } + /** + * Resolves a decorator as if it were a call expression. + */ function resolveDecorator(node: Decorator, candidatesOutArray: Signature[]): Signature { let funcType = checkExpression(node.expression); let apparentType = getApparentType(funcType); @@ -7446,43 +7568,16 @@ module ts { return resolveUntypedCall(node); } - let decoratorKind: string; - switch (node.parent.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - decoratorKind = "class"; - break; - - case SyntaxKind.Parameter: - decoratorKind = "parameter"; - break; - - case SyntaxKind.PropertyDeclaration: - decoratorKind = "property"; - break; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - decoratorKind = "method"; - break; - - default: - Debug.fail("Invalid decorator target."); - break; - } - - let diagnosticChainHead = chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression, decoratorKind); + let headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); if (!callSignatures.length) { - let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); - errorInfo = concatenateDiagnosticMessageChains(diagnosticChainHead, errorInfo); + let errorInfo: DiagnosticMessageChain; + errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + errorInfo = chainDiagnosticMessages(errorInfo, headMessage); diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo)); return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, diagnosticChainHead); + return resolveCall(node, callSignatures, candidatesOutArray, headMessage); } // candidatesOutArray is passed by signature help in the language service, and collectCandidates @@ -9134,24 +9229,28 @@ module ts { } let expectedReturnType: Type; - let diagnosticChainHead: DiagnosticMessageChain; - let decoratorKind: string; + let headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); + let errorInfo: DiagnosticMessageChain; switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: let classSymbol = getSymbolOfNode(node.parent); let classConstructorType = getTypeOfSymbol(classSymbol); expectedReturnType = getUnionType([classConstructorType, voidType]); - decoratorKind = "class"; break; case SyntaxKind.Parameter: expectedReturnType = voidType; - decoratorKind = "parameter"; - break; + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.The_return_type_of_a_parameter_decorator_function_must_be_either_void_or_any); + break; + case SyntaxKind.PropertyDeclaration: expectedReturnType = voidType; - decoratorKind = "property"; + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.The_return_type_of_a_property_decorator_function_must_be_either_void_or_any); break; case SyntaxKind.MethodDeclaration: @@ -9160,23 +9259,15 @@ module ts { let methodType = getTypeOfNode(node.parent); let descriptorType = createTypedPropertyDescriptorType(methodType); expectedReturnType = getUnionType([descriptorType, voidType]); - decoratorKind = "method"; break; } - if (expectedReturnType === voidType) { - diagnosticChainHead = chainDiagnosticMessages( - diagnosticChainHead, - Diagnostics.The_return_type_of_a_0_decorator_function_must_be_either_void_or_any, - decoratorKind); - } - - diagnosticChainHead = chainDiagnosticMessages( - diagnosticChainHead, - Diagnostics.Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression, - decoratorKind); - - checkTypeAssignableTo(returnType, expectedReturnType, node, /*headMessage*/ undefined, diagnosticChainHead); + checkTypeAssignableTo( + returnType, + expectedReturnType, + node, + headMessage, + errorInfo); } /** Checks a type reference node as an expression. */ @@ -11815,6 +11906,17 @@ module ts { return checkExpression(expr); } + /** + * Gets either the static or instance type of a class element, based on + * whether the element is declared as "static". + */ + function getParentTypeOfClassElement(node: ClassElement) { + let classSymbol = getSymbolOfNode(node.parent); + return node.flags & NodeFlags.Static + ? getTypeOfSymbol(classSymbol) + : getDeclaredTypeOfSymbol(classSymbol); + } + // Return the list of properties of the given type, augmented with properties from Function // if the type has call or construct signatures function getAugmentedPropertiesOfType(type: Type): Symbol[] { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index a1b776611f7..1653b673503 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -174,8 +174,12 @@ module ts { Type_expected_0_is_a_reserved_word_in_strict_mode: { code: 1215, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode" }, Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, Export_assignment_is_not_supported_when_module_flag_is_system: { code: 1218, category: DiagnosticCategory.Error, key: "Export assignment is not supported when '--module' flag is 'system'." }, - The_return_type_of_a_0_decorator_function_must_be_either_void_or_any: { code: 1219, category: DiagnosticCategory.Error, key: "The return type of a {0} decorator function must be either 'void' or 'any'." }, - Unable_to_resolve_signature_of_0_decorator_when_called_as_an_expression: { code: 1220, category: DiagnosticCategory.Error, key: "Unable to resolve signature of {0} decorator when called as an expression." }, + The_return_type_of_a_property_decorator_function_must_be_either_void_or_any: { code: 1219, category: DiagnosticCategory.Error, key: "The return type of a property decorator function must be either 'void' or 'any'." }, + The_return_type_of_a_parameter_decorator_function_must_be_either_void_or_any: { code: 1220, category: DiagnosticCategory.Error, key: "The return type of a parameter decorator function must be either 'void' or 'any'." }, + Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression: { code: 1221, category: DiagnosticCategory.Error, key: "Unable to resolve signature of class decorator when called as an expression." }, + Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression: { code: 1222, category: DiagnosticCategory.Error, key: "Unable to resolve signature of parameter decorator when called as an expression." }, + Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression: { code: 1223, category: DiagnosticCategory.Error, key: "Unable to resolve signature of property decorator when called as an expression." }, + Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression: { code: 1224, category: DiagnosticCategory.Error, key: "Unable to resolve signature of method decorator when called as an expression." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 27238db5d95..006e1d6f1a9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -683,14 +683,31 @@ "category": "Error", "code": 1218 }, - "The return type of a {0} decorator function must be either 'void' or 'any'.": { + "The return type of a property decorator function must be either 'void' or 'any'.": { "category": "Error", "code": 1219 }, - "Unable to resolve signature of {0} decorator when called as an expression.": { + "The return type of a parameter decorator function must be either 'void' or 'any'.": { "category": "Error", "code": 1220 }, + + "Unable to resolve signature of class decorator when called as an expression.": { + "category": "Error", + "code": 1221 + }, + "Unable to resolve signature of parameter decorator when called as an expression.": { + "category": "Error", + "code": 1222 + }, + "Unable to resolve signature of property decorator when called as an expression.": { + "category": "Error", + "code": 1223 + }, + "Unable to resolve signature of method decorator when called as an expression.": { + "category": "Error", + "code": 1224 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/tests/baselines/reference/decoratorOnClass8.errors.txt b/tests/baselines/reference/decoratorOnClass8.errors.txt index b5e27b4b3cb..adda3c19095 100644 --- a/tests/baselines/reference/decoratorOnClass8.errors.txt +++ b/tests/baselines/reference/decoratorOnClass8.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220: Unable to resolve signature of class decorator when called as an expression. +tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1221: Unable to resolve signature of class decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -7,7 +7,7 @@ tests/cases/conformance/decorators/class/decoratorOnClass8.ts(3,1): error TS1220 @dec() ~~~~~~ -!!! error TS1220: Unable to resolve signature of class decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1221: Unable to resolve signature of class decorator when called as an expression. +!!! error TS1221: Supplied parameters do not match any signature of call target. class C { } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt index 1d94f08f2a2..6499aa44e53 100644 --- a/tests/baselines/reference/decoratorOnClassMethod10.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod10.errors.txt @@ -1,6 +1,5 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6): error TS1220: Unable to resolve signature of method decorator when called as an expression. - Argument of type 'C' is not assignable to parameter of type 'Function'. - Property 'apply' is missing in type 'C'. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6): error TS2345: Argument of type 'C' is not assignable to parameter of type 'Function'. + Property 'apply' is missing in type 'C'. ==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts (1 errors) ==== @@ -9,7 +8,6 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod10.ts(4,6) class C { @dec method() {} ~~~ -!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. -!!! error TS1220: Argument of type 'C' is not assignable to parameter of type 'Function'. -!!! error TS1220: Property 'apply' is missing in type 'C'. +!!! error TS2345: Argument of type 'C' is not assignable to parameter of type 'Function'. +!!! error TS2345: Property 'apply' is missing in type 'C'. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod6.errors.txt b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt index 2231d0da56d..206480dd135 100644 --- a/tests/baselines/reference/decoratorOnClassMethod6.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod6.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1220: Unable to resolve signature of method decorator when called as an expression. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1224: Unable to resolve signature of method decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): class C { @dec ["method"]() {} ~~~~ -!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1224: Unable to resolve signature of method decorator when called as an expression. +!!! error TS1224: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassMethod8.errors.txt b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt index d80fe7e05f7..832b8efbb34 100644 --- a/tests/baselines/reference/decoratorOnClassMethod8.errors.txt +++ b/tests/baselines/reference/decoratorOnClassMethod8.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): error TS1220: Unable to resolve signature of method decorator when called as an expression. +tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): error TS1224: Unable to resolve signature of method decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod8.ts(4,5): class C { @dec method() {} ~~~~ -!!! error TS1220: Unable to resolve signature of method decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1224: Unable to resolve signature of method decorator when called as an expression. +!!! error TS1224: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty11.errors.txt b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt index 8dad5dc955f..9b153135639 100644 --- a/tests/baselines/reference/decoratorOnClassProperty11.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty11.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1223: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts( class C { @dec prop; ~~~~ -!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1223: Unable to resolve signature of property decorator when called as an expression. +!!! error TS1223: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt index eca97e803e0..8fa543a2734 100644 --- a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4,5): error TS1223: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty6.ts(4 class C { @dec prop; ~~~~ -!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1223: Unable to resolve signature of property decorator when called as an expression. +!!! error TS1223: Supplied parameters do not match any signature of call target. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt index 7f2249e5934..a467cfe5a27 100644 --- a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS1220: Unable to resolve signature of property decorator when called as an expression. +tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4,5): error TS1223: Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target. @@ -8,6 +8,6 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty7.ts(4 class C { @dec prop; ~~~~ -!!! error TS1220: Unable to resolve signature of property decorator when called as an expression. -!!! error TS1220: Supplied parameters do not match any signature of call target. +!!! error TS1223: Unable to resolve signature of property decorator when called as an expression. +!!! error TS1223: Supplied parameters do not match any signature of call target. } \ No newline at end of file From 87d0af10d00d49d8722e8264dbc0536a7812fb92 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 29 May 2015 11:00:19 -0700 Subject: [PATCH 4/5] Moved call for getSpreadArgumentIndex in hasCorrectArity --- src/compiler/checker.ts | 3 ++- src/compiler/diagnosticMessages.json | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 57e1f8190f0..04ff7a1eaa5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6628,6 +6628,7 @@ module ts { let typeArguments: NodeArray; // Type arguments (undefined if none) let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments let isDecorator: boolean; + let spreadArgIndex = -1; if (node.kind === SyntaxKind.TaggedTemplateExpression) { let tagExpression = node; @@ -6675,6 +6676,7 @@ module ts { callIsIncomplete = (callExpression).arguments.end === callExpression.end; typeArguments = callExpression.typeArguments; + spreadArgIndex = getSpreadArgumentIndex(args); } // If the user supplied type arguments, but the number of type arguments does not match @@ -6687,7 +6689,6 @@ module ts { // If spread arguments are present, check that they correspond to a rest parameter. If so, no // further checking is necessary. - let spreadArgIndex = !isDecorator ? getSpreadArgumentIndex(args) : -1; if (spreadArgIndex >= 0) { return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 006e1d6f1a9..264f2fdb55b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -691,7 +691,6 @@ "category": "Error", "code": 1220 }, - "Unable to resolve signature of class decorator when called as an expression.": { "category": "Error", "code": 1221 From ef697f6307d514cb378b161128f6d74ffb0079c6 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 23 Jun 2015 14:00:05 -0700 Subject: [PATCH 5/5] PR feedback --- src/compiler/checker.ts | 46 +++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2c4e18699d7..3db99a12686 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6769,9 +6769,20 @@ module ts { let argCount = getEffectiveArgumentCount(node, args, signature); for (let i = 0; i < argCount; i++) { let arg = getEffectiveArgument(node, args, i); - if (!arg || arg.kind !== SyntaxKind.OmittedExpression) { + // If the effective argument is 'undefined', then it is an argument that is present but is synthetic. + if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) { let paramType = getTypeAtPosition(signature, i); - let argType = getEffectiveArgumentType(node, i, arg, paramType, excludeArgument, inferenceMapper, /*reportErrors*/ false); + let argType = getEffectiveArgumentType(node, i, arg); + + // If the effective argument type is 'undefined', there is no synthetic type + // for the argument. In that case, we should check the argument. + if (argType === undefined) { + // For context sensitive arguments we pass the identityMapper, which is a signal to treat all + // context sensitive function expressions as wildcards + let mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; + argType = checkExpressionWithContextualType(arg, paramType, mapper); + } + inferTypes(context, argType, paramType); } } @@ -6830,10 +6841,19 @@ module ts { let argCount = getEffectiveArgumentCount(node, args, signature); for (let i = 0; i < argCount; i++) { let arg = getEffectiveArgument(node, args, i); - if (!arg || arg.kind !== SyntaxKind.OmittedExpression) { + // If the effective argument is 'undefined', then it is an argument that is present but is synthetic. + 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) let paramType = getTypeAtPosition(signature, i); - let argType = getEffectiveArgumentType(node, i, arg, paramType, excludeArgument, /*inferenceMapper*/ undefined, reportErrors); + let argType = getEffectiveArgumentType(node, i, arg); + + // If the effective argument type is 'undefined', there is no synthetic type + // for the argument. In that case, we should check the argument. + if (argType === undefined) { + argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors + ? getStringLiteralType(arg) + : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + } // Use argument expression as error location when reporting errors let errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined; @@ -7126,7 +7146,7 @@ module ts { /** * Gets the effective argument type for an argument in a call expression. */ - function getEffectiveArgumentType(node: CallLikeExpression, argIndex: number, arg: Expression, paramType: Type, excludeArgument: boolean[], inferenceMapper: TypeMapper, reportErrors: boolean): Type { + function getEffectiveArgumentType(node: CallLikeExpression, argIndex: number, arg: Expression): Type { // Decorators provide special arguments, a tagged template expression provides // a special first argument, and string literals get string literal types // unless we're reporting errors @@ -7136,20 +7156,10 @@ module ts { else if (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) { return globalTemplateStringsArrayType; } - else if (!inferenceMapper && !reportErrors && arg.kind === SyntaxKind.StringLiteral) { - return getStringLiteralType(arg); - } - else { - let mapper: TypeMapper; - if (inferenceMapper) { - mapper = excludeArgument && excludeArgument[argIndex] !== undefined ? identityMapper : inferenceMapper; - } - else { - mapper = excludeArgument && excludeArgument[argIndex] ? identityMapper : undefined; - } - return checkExpressionWithContextualType(arg, paramType, mapper); - } + // This is not a synthetic argument, so we return 'undefined' + // to signal that the caller needs to check the argument. + return undefined; } /**