Skip to content

Commit b49e277

Browse files
committed
Addressing CR feedback
1 parent 816abb1 commit b49e277

4 files changed

Lines changed: 72 additions & 21 deletions

File tree

src/compiler/checker.ts

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,25 +1660,34 @@ module ts {
16601660
return classType.typeParameters ? createTypeReference(<GenericType>classType, map(classType.typeParameters, _ => anyType)) : classType;
16611661
}
16621662

1663+
// Return the type of the given property in the given type, or undefined if no such property exists
16631664
function getTypeOfPropertyOfType(type: Type, name: string): Type {
16641665
var prop = getPropertyOfType(type, name);
16651666
return prop ? getTypeOfSymbol(prop) : undefined;
16661667
}
16671668

1669+
// Return the inferred type for a binding element
16681670
function getTypeForBindingElement(declaration: BindingElement): Type {
16691671
var pattern = <BindingPattern>declaration.parent;
16701672
var parentType = getTypeForVariableDeclaration(<VariableDeclaration>pattern.parent);
1673+
// If parent has the unknown (error) type, then so does this binding element
16711674
if (parentType === unknownType) {
16721675
return unknownType;
16731676
}
1677+
// If no type was specified or inferred for parent, or if the specified or inferred type is any,
1678+
// infer from the initializer of the binding element if one is present. Otherwise, go with the
1679+
// undefined or any type of the parent.
16741680
if (!parentType || parentType === anyType) {
16751681
if (declaration.initializer) {
16761682
return checkExpressionCached(declaration.initializer);
16771683
}
16781684
return parentType;
16791685
}
16801686
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
1687+
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
16811688
var name = declaration.propertyName || <Identifier>declaration.name;
1689+
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
1690+
// or otherwise the type of the string index signature.
16821691
var type = getTypeOfPropertyOfType(parentType, name.text) ||
16831692
isNumericName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
16841693
getIndexTypeOfType(parentType, IndexKind.String);
@@ -1688,19 +1697,22 @@ module ts {
16881697
}
16891698
return type;
16901699
}
1700+
// For an array binding element the specified or inferred type of the parent must be assignable to any[]
16911701
if (!isTypeAssignableTo(parentType, anyArrayType)) {
16921702
error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType));
16931703
return unknownType;
16941704
}
1705+
// Use specific property type when parent is a tuple or numeric index type when parent is an array
16951706
var propName = "" + indexOf(pattern.elements, declaration);
1696-
var type = isTupleType(parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number);
1707+
var type = isTupleLikeType(parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number);
16971708
if (!type) {
16981709
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
16991710
return unknownType;
17001711
}
17011712
return type;
17021713
}
17031714

1715+
// Return the inferred type for a variable, parameter, or property declaration
17041716
function getTypeForVariableDeclaration(declaration: VariableDeclaration): Type {
17051717
// A variable declared in a for..in statement is always of type any
17061718
if (declaration.parent.kind === SyntaxKind.ForInStatement) {
@@ -1732,15 +1744,17 @@ module ts {
17321744
if (declaration.initializer) {
17331745
return checkExpressionCached(declaration.initializer);
17341746
}
1735-
// If it is a short-hand property assignment; Use the type of the identifier
1747+
// If it is a short-hand property assignment, use the type of the identifier
17361748
if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
1737-
var type = checkIdentifier(<Identifier>declaration.name);
1738-
return type
1749+
return checkIdentifier(<Identifier>declaration.name);
17391750
}
17401751
// No type specified and nothing can be inferred
17411752
return undefined;
17421753
}
17431754

1755+
// Return the type implied by a binding pattern element. This is the type of the initializer of the element if
1756+
// one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
1757+
// pattern. Otherwise, it is the type any.
17441758
function getTypeFromBindingElement(element: BindingElement): Type {
17451759
if (element.initializer) {
17461760
return getWidenedType(checkExpressionCached(element.initializer));
@@ -1751,6 +1765,13 @@ module ts {
17511765
return anyType;
17521766
}
17531767

1768+
// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
1769+
// and without regard to its context (i.e. without regard any type annotation or initializer associated with the
1770+
// declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
1771+
// and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
1772+
// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
1773+
// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
1774+
// the parameter.
17541775
function getTypeFromBindingPattern(pattern: BindingPattern): Type {
17551776
if (pattern.kind === SyntaxKind.ArrayBindingPattern) {
17561777
return createTupleType(map(pattern.elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e)));
@@ -1766,14 +1787,28 @@ module ts {
17661787
return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
17671788
}
17681789

1790+
// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
1791+
// specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
1792+
// is a bit more involved. For example:
1793+
//
1794+
// var [x, s = ""] = [1, "one"];
1795+
//
1796+
// Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the
1797+
// binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the
1798+
// tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string.
17691799
function getWidenedTypeForVariableDeclaration(declaration: VariableDeclaration, reportErrors?: boolean): Type {
17701800
var type = getTypeForVariableDeclaration(declaration);
17711801
if (type) {
17721802
if (reportErrors) {
17731803
reportErrorsFromWidening(declaration, type);
17741804
}
1805+
// During a normal type check we'll never get to here with a property assignment (the check of the containing
1806+
// object literal uses a different path). We exclude widening only so that language services and type verification
1807+
// tools see the actual type.
17751808
return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type;
17761809
}
1810+
// If no type was specified and nothing could be inferred, and if the declaration specifies a binding pattern, use
1811+
// the type implied by the binding pattern
17771812
if (isBindingPattern(declaration.name)) {
17781813
return getTypeFromBindingPattern(<BindingPattern>declaration.name);
17791814
}
@@ -4052,7 +4087,7 @@ module ts {
40524087
return type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType;
40534088
}
40544089

4055-
function isTupleType(type: Type): boolean {
4090+
function isTupleLikeType(type: Type): boolean {
40564091
return !!getPropertyOfType(type, "0");
40574092
}
40584093

@@ -4890,9 +4925,10 @@ module ts {
48904925
}
48914926

48924927
// In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer
4893-
// expression is the type of the variable, parameter or property. In a parameter declaration of a contextually
4894-
// typed function expression, the contextual type of an initializer expression is the contextual type of the
4895-
// parameter.
4928+
// expression is the type of the variable, parameter or property. Otherwise, in a parameter declaration of a
4929+
// contextually typed function expression, the contextual type of an initializer expression is the contextual type
4930+
// of the parameter. Otherwise, in a variable or parameter declaration with a binding pattern name, the contextual
4931+
// type of an initializer expression is the type implied by the binding pattern.
48964932
function getContextualTypeForInitializerExpression(node: Expression): Type {
48974933
var declaration = <VariableOrParameterDeclaration>node.parent;
48984934
if (node === declaration.initializer) {
@@ -5001,8 +5037,8 @@ module ts {
50015037
}
50025038

50035039
// Return true if the given contextual type is a tuple-like type
5004-
function contextualTypeIsTupleType(type: Type): boolean {
5005-
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => isTupleType(t)) : isTupleType(type));
5040+
function contextualTypeIsTupleLikeType(type: Type): boolean {
5041+
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => isTupleLikeType(t)) : isTupleLikeType(type));
50065042
}
50075043

50085044
// Return true if the given contextual type provides an index signature of the given kind
@@ -5160,6 +5196,9 @@ module ts {
51605196
return mapper && mapper !== identityMapper;
51615197
}
51625198

5199+
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
5200+
// assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
5201+
// an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'.
51635202
function isAssignmentTarget(node: Node): boolean {
51645203
var parent = node.parent;
51655204
if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operator === SyntaxKind.EqualsToken && (<BinaryExpression>parent).left === node) {
@@ -5181,7 +5220,7 @@ module ts {
51815220
}
51825221
var elementTypes = map(elements, e => checkExpression(e, contextualMapper));
51835222
var contextualType = getContextualType(node);
5184-
if ((contextualType && contextualTypeIsTupleType(contextualType)) || isAssignmentTarget(node)) {
5223+
if ((contextualType && contextualTypeIsTupleLikeType(contextualType)) || isAssignmentTarget(node)) {
51855224
return createTupleType(elementTypes);
51865225
}
51875226
return createArrayType(getUnionType(elementTypes));
@@ -6492,7 +6531,7 @@ module ts {
64926531
var p = properties[i];
64936532
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
64946533
// TODO(andersh): Computed property support
6495-
var name = <Identifier>((<PropertyDeclaration>p).name);
6534+
var name = <Identifier>(<PropertyDeclaration>p).name;
64966535
var type = sourceType.flags & TypeFlags.Any ? sourceType :
64976536
getTypeOfPropertyOfType(sourceType, name.text) ||
64986537
isNumericName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
@@ -6523,7 +6562,7 @@ module ts {
65236562
if (e.kind !== SyntaxKind.OmittedExpression) {
65246563
var propName = "" + i;
65256564
var type = sourceType.flags & TypeFlags.Any ? sourceType :
6526-
isTupleType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) :
6565+
isTupleLikeType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) :
65276566
getIndexTypeOfType(sourceType, IndexKind.Number);
65286567
if (type) {
65296568
checkDestructuringAssignment(e, type, contextualMapper);

src/compiler/emitter.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,13 +1881,18 @@ module ts {
18811881
writeFile(compilerHost, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
18821882
}
18831883

1884-
function createTempVariable(location: Node): Identifier {
1885-
do {
1886-
// First _a..._z, then _0, _1, ...
1887-
var name = "_" + (tempCount < 26 ? String.fromCharCode(tempCount + 0x61) : tempCount - 26);
1884+
// Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the
1885+
// name should be one that is appropriate for a for loop variable.
1886+
function createTempVariable(location: Node, forLoopVariable?: boolean): Identifier {
1887+
var name = forLoopVariable ? "_i" : undefined;
1888+
while (true) {
1889+
if (name && resolver.isUnknownIdentifier(location, name)) {
1890+
break;
1891+
}
1892+
// _a .. _h, _j ... _z, _0, _1, ...
1893+
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0: 1) + CharacterCodes.a) : tempCount - 25);
18881894
tempCount++;
18891895
}
1890-
while (!resolver.isUnknownIdentifier(location, name));
18911896
var result = <Identifier>createNode(SyntaxKind.Identifier);
18921897
result.text = name;
18931898
return result;
@@ -2758,6 +2763,8 @@ module ts {
27582763

27592764
function emitDestructuring(root: BinaryExpression | BindingElement, value?: Expression) {
27602765
var emitCount = 0;
2766+
// An exported declaration is actually emitted as an assignment (to a property on the module object), so
2767+
// temporary variables in an exported declaration need to have real declarations elsewhere.
27612768
var isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(root.flags & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter;
27622769
if (root.kind === SyntaxKind.BinaryExpression) {
27632770
emitAssignmentExpression(<BinaryExpression>root);
@@ -3038,7 +3045,7 @@ module ts {
30383045
if (hasRestParameters(node)) {
30393046
var restIndex = node.parameters.length - 1;
30403047
var restParam = node.parameters[restIndex];
3041-
var tempName = createTempVariable(node).text;
3048+
var tempName = createTempVariable(node, /*forLoopVariable*/ true).text;
30423049
writeLine();
30433050
emitLeadingComments(restParam);
30443051
emitStart(restParam);

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ module ts {
812812
return undefined;
813813
}
814814

815-
enum ParsingContext {
815+
const enum ParsingContext {
816816
SourceElements, // Elements in source file
817817
ModuleElements, // Elements in module declaration
818818
BlockStatements, // Statements in block

src/services/navigationBar.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@ module ts.NavigationBar {
4646
case SyntaxKind.VariableStatement:
4747
forEach((<VariableStatement>node).declarations, visit);
4848
break;
49+
case SyntaxKind.ObjectBindingPattern:
50+
case SyntaxKind.ArrayBindingPattern:
51+
forEach((<BindingPattern>node).elements, visit);
52+
break;
4953
case SyntaxKind.VariableDeclaration:
5054
if (isBindingPattern(node)) {
51-
forEach((<BindingPattern>(<VariableDeclaration>node).name).elements, visit);
55+
visit((<VariableDeclaration>node).name);
5256
break;
5357
}
58+
// Fall through
5459
case SyntaxKind.ClassDeclaration:
5560
case SyntaxKind.EnumDeclaration:
5661
case SyntaxKind.InterfaceDeclaration:

0 commit comments

Comments
 (0)