From 67c88a258837a20b0558decaf8d60e51757563e2 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 20 May 2015 16:38:13 -0700 Subject: [PATCH] Initial PR feedback --- package.json | 2 +- src/compiler/checker.ts | 56 +++++++++++-------- src/services/shims.ts | 2 +- .../inferentialTypingObjectLiteralMethod1.js | 9 +++ ...erentialTypingObjectLiteralMethod1.symbols | 39 +++++++++++++ ...nferentialTypingObjectLiteralMethod1.types | 43 ++++++++++++++ .../inferentialTypingObjectLiteralMethod2.js | 9 +++ ...erentialTypingObjectLiteralMethod2.symbols | 39 +++++++++++++ ...nferentialTypingObjectLiteralMethod2.types | 43 ++++++++++++++ .../inferentialTypingObjectLiteralMethod1.ts | 5 ++ .../inferentialTypingObjectLiteralMethod2.ts | 5 ++ 11 files changed, 226 insertions(+), 26 deletions(-) create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod1.js create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod1.symbols create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod1.types create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod2.js create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod2.symbols create mode 100644 tests/baselines/reference/inferentialTypingObjectLiteralMethod2.types create mode 100644 tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts create mode 100644 tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts diff --git a/package.json b/package.json index ca137dcfb40..d6a8f538b78 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "http://typescriptlang.org/", - "version": "1.5.2", + "version": "1.5.3", "license": "Apache-2.0", "description": "TypeScript is a language for application scale JavaScript development", "keywords": [ diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c85c159e537..9396745a5fa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2154,7 +2154,7 @@ module ts { // checkRightHandSideOfForOf will return undefined if the for-of expression type was // missing properties/signatures required to get its iteratedType (like // [Symbol.iterator] or next). This may be because we accessed properties from anyType, - // or it may have led to an error inside getElementTypeFromIterable. + // or it may have led to an error inside getElementTypeOfIterable. return checkRightHandSideOfForOf((declaration.parent.parent).expression) || anyType; } if (isBindingPattern(declaration.parent)) { @@ -3511,6 +3511,9 @@ module ts { return globalESSymbolConstructorSymbol || (globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol")); } + /** + * Instantiates a global type that is generic with some element type, and returns that instantiation. + */ function createTypeFromGenericGlobalType(genericGlobalType: GenericType, elementType: Type): Type { return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, [elementType]) : emptyObjectType; } @@ -5794,7 +5797,7 @@ module ts { if (contextualReturnType) { return node.asteriskToken ? contextualReturnType - : getElementTypeFromIterableIterator(contextualReturnType); + : getElementTypeOfIterableIterator(contextualReturnType); } } @@ -5804,9 +5807,12 @@ module ts { function getContextualReturnType(functionDecl: FunctionLikeDeclaration): Type { // If the containing function has a return type annotation, is a constructor, or is a get accessor whose // corresponding set accessor has a type annotation, return statements in the function are contextually typed - if (functionDecl.type || functionDecl.kind === SyntaxKind.Constructor || functionDecl.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(functionDecl.symbol, SyntaxKind.SetAccessor))) { + if (functionDecl.type || + functionDecl.kind === SyntaxKind.Constructor || + functionDecl.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(functionDecl.symbol, SyntaxKind.SetAccessor))) { return getReturnTypeOfSignature(getSignatureFromDeclaration(functionDecl)); } + // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature // and that call signature is non-generic, return statements are contextually typed by the return type of the signature let signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl); @@ -5951,7 +5957,7 @@ module ts { let index = indexOf(arrayLiteral.elements, node); return getTypeOfPropertyOfContextualType(type, "" + index) || getIndexTypeOfContextualType(type, IndexKind.Number) - || (languageVersion >= ScriptTarget.ES6 ? getElementTypeFromIterable(type, /*errorNode*/ undefined) : undefined); + || (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(type, /*errorNode*/ undefined) : undefined); } return undefined; } @@ -6142,7 +6148,7 @@ module ts { // if there is no index type / iterated type. let restArrayType = checkExpression((e).expression, contextualMapper); let restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) || - (languageVersion >= ScriptTarget.ES6 ? getElementTypeFromIterable(restArrayType, /*errorNode*/ undefined) : undefined); + (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { elementTypes.push(restElementType); @@ -7337,7 +7343,8 @@ module ts { } else { let types: Type[]; - if (func.asteriskToken) { + let funcIsGenerator = !!func.asteriskToken; + if (funcIsGenerator) { types = checkAndAggregateYieldOperandTypes(func.body, contextualMapper); if (types.length === 0) { let iterableIteratorAny = createIterableIteratorType(anyType); @@ -7359,7 +7366,7 @@ module ts { // Otherwise we require the yield/return expressions to have a best common supertype. type = contextualSignature ? getUnionType(types) : getCommonSupertype(types); if (!type) { - if (func.asteriskToken) { + if (funcIsGenerator) { error(func, Diagnostics.No_best_common_type_exists_among_yield_expressions); return createIterableIteratorType(unknownType); } @@ -7369,7 +7376,7 @@ module ts { } } - if (func.asteriskToken) { + if (funcIsGenerator) { type = createIterableIteratorType(type); } } @@ -8069,20 +8076,21 @@ module ts { if (node.expression) { let func = getContainingFunction(node); - // If this is correct code, the func should always have a star. After all, + // If the user's code is syntactically correct, the func should always have a star. After all, // we are in a yield context. if (func && func.asteriskToken) { let expressionType = checkExpressionCached(node.expression, /*contextualMapper*/ undefined); let expressionElementType: Type; - if (node.asteriskToken) { + let nodeIsYieldStar = !!node.asteriskToken; + if (nodeIsYieldStar) { expressionElementType = checkElementTypeOfIterable(expressionType, node.expression); } // There is no point in doing an assignability check if the function - // has no explicit return type, because the return type is directly computed + // has no explicit return type because the return type is directly computed // from the yield expressions. if (func.type) { - let signatureElementType = getElementTypeFromIterableIterator(getTypeFromTypeNode(func.type)) || unknownType; - if (node.asteriskToken) { + let signatureElementType = getElementTypeOfIterableIterator(getTypeFromTypeNode(func.type)) || anyType; + if (nodeIsYieldStar) { checkTypeAssignableTo(expressionElementType, signatureElementType, node.expression, /*headMessage*/ undefined); } else { @@ -8092,7 +8100,7 @@ module ts { } } - // Both yield and yield* expressions are any + // Both yield and yield* expressions have type 'any' return anyType; } @@ -8386,7 +8394,7 @@ module ts { error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation); } else { - let generatorElementType = getElementTypeFromIterableIterator(returnType) || anyType; + let generatorElementType = getElementTypeOfIterableIterator(returnType) || anyType; let iterableIteratorInstantiation = createIterableIteratorType(generatorElementType); // Naively, one could check that IterableIterator is assignable to the return type annotation. @@ -9597,7 +9605,7 @@ module ts { // iteratedType will be undefined if the rightType was missing properties/signatures // required to get its iteratedType (like [Symbol.iterator] or next). This may be // because we accessed properties from anyType, or it may have led to an error inside - // getElementTypeFromIterable. + // getElementTypeOfIterable. if (iteratedType) { checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined); } @@ -9695,7 +9703,7 @@ module ts { * When errorNode is undefined, it means we should not report any errors. */ function checkElementTypeOfIterable(iterable: Type, errorNode: Node): Type { - let elementType = getElementTypeFromIterable(iterable, errorNode); + let elementType = getElementTypeOfIterable(iterable, errorNode); // Now even though we have extracted the iteratedType, we will have to validate that the type // passed in is actually an Iterable. if (errorNode && elementType) { @@ -9705,7 +9713,7 @@ module ts { return elementType || anyType; } - function getElementTypeFromIterable(iterable: Type, errorNode: Node): Type { + function getElementTypeOfIterable(iterable: Type, errorNode: Node): Type { // We want to treat type as an iterable, and get the type it is an iterable of. The iterable // must have the following structure (annotated with the names of the variables below): // @@ -9751,15 +9759,15 @@ module ts { return undefined; } - typeAsIterable.iterableElementType = getElementTypeFromIterator(getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature)), errorNode); + typeAsIterable.iterableElementType = getElementTypeOfIterator(getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature)), errorNode); } } return typeAsIterable.iterableElementType; } - function getElementTypeFromIterator(iterator: Type, errorNode: Node): Type { - // This function has very similar logic as getElementTypeFromIterable, except that it operates on + function getElementTypeOfIterator(iterator: Type, errorNode: Node): Type { + // This function has very similar logic as getElementTypeOfIterable, except that it operates on // Iterators instead of Iterables. Here is the structure: // // { // iterator @@ -9815,7 +9823,7 @@ module ts { return typeAsIterator.iteratorElementType; } - function getElementTypeFromIterableIterator(iterableIterator: Type): Type { + function getElementTypeOfIterableIterator(iterableIterator: Type): Type { if (allConstituentTypesHaveKind(iterableIterator, TypeFlags.Any)) { return undefined; } @@ -9826,8 +9834,8 @@ module ts { return (iterableIterator).typeArguments[0]; } - return getElementTypeFromIterable(iterableIterator, /*errorNode*/ undefined) || - getElementTypeFromIterator(iterableIterator, /*errorNode*/ undefined); + return getElementTypeOfIterable(iterableIterator, /*errorNode*/ undefined) || + getElementTypeOfIterator(iterableIterator, /*errorNode*/ undefined); } /** diff --git a/src/services/shims.ts b/src/services/shims.ts index 27c70ddc878..d3f59737538 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -989,4 +989,4 @@ module TypeScript.Services { } /* @internal */ -let toolsVersion = "1.4"; +let toolsVersion = "1.5"; diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.js b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.js new file mode 100644 index 00000000000..ad58c7e22ab --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.js @@ -0,0 +1,9 @@ +//// [inferentialTypingObjectLiteralMethod1.ts] +interface Int { + method(x: T): U; +} +declare function foo(x: T, y: Int, z: Int): T; +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); + +//// [inferentialTypingObjectLiteralMethod1.js] +foo("", { method: function (p1) { return p1.length; } }, { method: function (p2) { return undefined; } }); diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.symbols b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.symbols new file mode 100644 index 00000000000..13b69d045a3 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.symbols @@ -0,0 +1,39 @@ +=== tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts === +interface Int { +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 14)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 16)) + + method(x: T): U; +>method : Symbol(method, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 21)) +>x : Symbol(x, Decl(inferentialTypingObjectLiteralMethod1.ts, 1, 11)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 14)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 16)) +} +declare function foo(x: T, y: Int, z: Int): T; +>foo : Symbol(foo, Decl(inferentialTypingObjectLiteralMethod1.ts, 2, 1)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 21)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 23)) +>x : Symbol(x, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 27)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 21)) +>y : Symbol(y, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 32)) +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 21)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 23)) +>z : Symbol(z, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 46)) +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod1.ts, 0, 0)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 23)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 21)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod1.ts, 3, 21)) + +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); +>foo : Symbol(foo, Decl(inferentialTypingObjectLiteralMethod1.ts, 2, 1)) +>method : Symbol(method, Decl(inferentialTypingObjectLiteralMethod1.ts, 4, 9)) +>p1 : Symbol(p1, Decl(inferentialTypingObjectLiteralMethod1.ts, 4, 17)) +>p1.length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>p1 : Symbol(p1, Decl(inferentialTypingObjectLiteralMethod1.ts, 4, 17)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>method : Symbol(method, Decl(inferentialTypingObjectLiteralMethod1.ts, 4, 46)) +>p2 : Symbol(p2, Decl(inferentialTypingObjectLiteralMethod1.ts, 4, 54)) +>undefined : Symbol(undefined) + diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.types b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.types new file mode 100644 index 00000000000..13df1f6f662 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod1.types @@ -0,0 +1,43 @@ +=== tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts === +interface Int { +>Int : Int +>T : T +>U : U + + method(x: T): U; +>method : (x: T) => U +>x : T +>T : T +>U : U +} +declare function foo(x: T, y: Int, z: Int): T; +>foo : (x: T, y: Int, z: Int) => T +>T : T +>U : U +>x : T +>T : T +>y : Int +>Int : Int +>T : T +>U : U +>z : Int +>Int : Int +>U : U +>T : T +>T : T + +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); +>foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }) : string +>foo : (x: T, y: Int, z: Int) => T +>"" : string +>{ method(p1) { return p1.length } } : { method(p1: string): number; } +>method : (p1: string) => number +>p1 : string +>p1.length : number +>p1 : string +>length : number +>{ method(p2) { return undefined } } : { method(p2: number): any; } +>method : (p2: number) => any +>p2 : number +>undefined : undefined + diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.js b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.js new file mode 100644 index 00000000000..2181c954dc0 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.js @@ -0,0 +1,9 @@ +//// [inferentialTypingObjectLiteralMethod2.ts] +interface Int { + [s: string]: (x: T) => U; +} +declare function foo(x: T, y: Int, z: Int): T; +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); + +//// [inferentialTypingObjectLiteralMethod2.js] +foo("", { method: function (p1) { return p1.length; } }, { method: function (p2) { return undefined; } }); diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.symbols b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.symbols new file mode 100644 index 00000000000..84c2e8f1820 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.symbols @@ -0,0 +1,39 @@ +=== tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts === +interface Int { +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 14)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 16)) + + [s: string]: (x: T) => U; +>s : Symbol(s, Decl(inferentialTypingObjectLiteralMethod2.ts, 1, 5)) +>x : Symbol(x, Decl(inferentialTypingObjectLiteralMethod2.ts, 1, 18)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 14)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 16)) +} +declare function foo(x: T, y: Int, z: Int): T; +>foo : Symbol(foo, Decl(inferentialTypingObjectLiteralMethod2.ts, 2, 1)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 21)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 23)) +>x : Symbol(x, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 27)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 21)) +>y : Symbol(y, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 32)) +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 21)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 23)) +>z : Symbol(z, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 46)) +>Int : Symbol(Int, Decl(inferentialTypingObjectLiteralMethod2.ts, 0, 0)) +>U : Symbol(U, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 23)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 21)) +>T : Symbol(T, Decl(inferentialTypingObjectLiteralMethod2.ts, 3, 21)) + +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); +>foo : Symbol(foo, Decl(inferentialTypingObjectLiteralMethod2.ts, 2, 1)) +>method : Symbol(method, Decl(inferentialTypingObjectLiteralMethod2.ts, 4, 9)) +>p1 : Symbol(p1, Decl(inferentialTypingObjectLiteralMethod2.ts, 4, 17)) +>p1.length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>p1 : Symbol(p1, Decl(inferentialTypingObjectLiteralMethod2.ts, 4, 17)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>method : Symbol(method, Decl(inferentialTypingObjectLiteralMethod2.ts, 4, 46)) +>p2 : Symbol(p2, Decl(inferentialTypingObjectLiteralMethod2.ts, 4, 54)) +>undefined : Symbol(undefined) + diff --git a/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.types b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.types new file mode 100644 index 00000000000..99e6968732b --- /dev/null +++ b/tests/baselines/reference/inferentialTypingObjectLiteralMethod2.types @@ -0,0 +1,43 @@ +=== tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts === +interface Int { +>Int : Int +>T : T +>U : U + + [s: string]: (x: T) => U; +>s : string +>x : T +>T : T +>U : U +} +declare function foo(x: T, y: Int, z: Int): T; +>foo : (x: T, y: Int, z: Int) => T +>T : T +>U : U +>x : T +>T : T +>y : Int +>Int : Int +>T : T +>U : U +>z : Int +>Int : Int +>U : U +>T : T +>T : T + +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); +>foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }) : string +>foo : (x: T, y: Int, z: Int) => T +>"" : string +>{ method(p1) { return p1.length } } : { [x: string]: (p1: string) => number; method(p1: string): number; } +>method : (p1: string) => number +>p1 : string +>p1.length : number +>p1 : string +>length : number +>{ method(p2) { return undefined } } : { [x: string]: (p2: number) => any; method(p2: number): any; } +>method : (p2: number) => any +>p2 : number +>undefined : undefined + diff --git a/tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts b/tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts new file mode 100644 index 00000000000..0ff6eb5d658 --- /dev/null +++ b/tests/cases/compiler/inferentialTypingObjectLiteralMethod1.ts @@ -0,0 +1,5 @@ +interface Int { + method(x: T): U; +} +declare function foo(x: T, y: Int, z: Int): T; +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); \ No newline at end of file diff --git a/tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts b/tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts new file mode 100644 index 00000000000..e04151a1749 --- /dev/null +++ b/tests/cases/compiler/inferentialTypingObjectLiteralMethod2.ts @@ -0,0 +1,5 @@ +interface Int { + [s: string]: (x: T) => U; +} +declare function foo(x: T, y: Int, z: Int): T; +foo("", { method(p1) { return p1.length } }, { method(p2) { return undefined } }); \ No newline at end of file