@@ -383,20 +383,72 @@ namespace ts {
383383 // return undefined if we can't find a symbol.
384384 }
385385
386- /** Returns true if node1 is defined before node 2**/
387- function isDefinedBefore(node1: Node, node2: Node): boolean {
388- let file1 = getSourceFileOfNode(node1);
389- let file2 = getSourceFileOfNode(node2);
390- if (file1 === file2) {
391- return node1.pos <= node2.pos;
386+ function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean {
387+ const declarationFile = getSourceFileOfNode(declaration);
388+ const useFile = getSourceFileOfNode(usage);
389+ if (declarationFile !== useFile) {
390+ if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) {
391+ // nodes are in different files and order cannot be determines
392+ return true;
393+ }
394+
395+ const sourceFiles = host.getSourceFiles();
396+ return indexOf(sourceFiles, declarationFile) <= indexOf(sourceFiles, useFile);
392397 }
393398
394- if (!compilerOptions.outFile && !compilerOptions.out) {
395- return true;
399+ if (declaration.pos <= usage.pos) {
400+ // declaration is before usage
401+ // still might be illegal if usage is in the initializer of the variable declaration
402+ return declaration.kind !== SyntaxKind.VariableDeclaration ||
403+ !isImmediatelyUsedInInitializerOfBlockScopedVariable(<VariableDeclaration>declaration, usage);
404+ }
405+
406+ // declaration is after usage
407+ // can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
408+ return isUsedInFunctionOrNonStaticProperty(declaration, usage);
409+
410+ function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
411+ const container = getEnclosingBlockScopeContainer(declaration);
412+
413+ if (declaration.parent.parent.kind === SyntaxKind.VariableStatement ||
414+ declaration.parent.parent.kind === SyntaxKind.ForStatement) {
415+ // variable statement/for statement case,
416+ // use site should not be inside variable declaration (initializer of declaration or binding element)
417+ return isSameScopeDescendentOf(usage, declaration, container);
418+ }
419+ else if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement ||
420+ declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
421+ // ForIn/ForOf case - use site should not be used in expression part
422+ let expression = (<ForInStatement | ForOfStatement>declaration.parent.parent).expression;
423+ return isSameScopeDescendentOf(usage, expression, container);
424+ }
396425 }
397426
398- let sourceFiles = host.getSourceFiles();
399- return indexOf(sourceFiles, file1) <= indexOf(sourceFiles, file2);
427+ function isUsedInFunctionOrNonStaticProperty(declaration: Declaration, usage: Node): boolean {
428+ const container = getEnclosingBlockScopeContainer(declaration);
429+ let current = usage;
430+ while (current) {
431+ if (current === container) {
432+ return false;
433+ }
434+
435+ if (isFunctionLike(current)) {
436+ return true;
437+ }
438+
439+ const initializerOfNonStaticProperty = current.parent &&
440+ current.parent.kind === SyntaxKind.PropertyDeclaration &&
441+ (current.parent.flags & NodeFlags.Static) === 0 &&
442+ (<PropertyDeclaration>current.parent).initializer === current;
443+
444+ if (initializerOfNonStaticProperty) {
445+ return true;
446+ }
447+
448+ current = current.parent;
449+ }
450+ return false;
451+ }
400452 }
401453
402454 // Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and
@@ -627,34 +679,7 @@ namespace ts {
627679
628680 Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined");
629681
630- // first check if usage is lexically located after the declaration
631- let isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation);
632- if (!isUsedBeforeDeclaration) {
633- // lexical check succeeded however code still can be illegal.
634- // - block scoped variables cannot be used in its initializers
635- // let x = x; // illegal but usage is lexically after definition
636- // - in ForIn/ForOf statements variable cannot be contained in expression part
637- // for (let x in x)
638- // for (let x of x)
639-
640- // climb up to the variable declaration skipping binding patterns
641- let variableDeclaration = <VariableDeclaration>getAncestor(declaration, SyntaxKind.VariableDeclaration);
642- let container = getEnclosingBlockScopeContainer(variableDeclaration);
643-
644- if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement ||
645- variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) {
646- // variable statement/for statement case,
647- // use site should not be inside variable declaration (initializer of declaration or binding element)
648- isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container);
649- }
650- else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement ||
651- variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
652- // ForIn/ForOf case - use site should not be used in expression part
653- let expression = (<ForInStatement | ForOfStatement>variableDeclaration.parent.parent).expression;
654- isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container);
655- }
656- }
657- if (isUsedBeforeDeclaration) {
682+ if (!isBlockScopedNameDeclaredBeforeUse(<Declaration>getAncestor(declaration, SyntaxKind.VariableDeclaration), errorLocation)) {
658683 error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name));
659684 }
660685 }
@@ -7984,6 +8009,11 @@ namespace ts {
79848009 return true;
79858010 }
79868011 // An instance property must be accessed through an instance of the enclosing class
8012+ if (type.flags & TypeFlags.ThisType) {
8013+ // get the original type -- represented as the type constraint of the 'this' type
8014+ type = getConstraintOfTypeParameter(<TypeParameter>type);
8015+ }
8016+
79878017 // TODO: why is the first part of this check here?
79888018 if (!(getTargetType(type).flags & (TypeFlags.Class | TypeFlags.Interface) && hasBaseType(<InterfaceType>type, enclosingClass))) {
79898019 error(node, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass));
@@ -10069,7 +10099,9 @@ namespace ts {
1006910099 let rightType = checkExpression(right, contextualMapper);
1007010100 switch (operator) {
1007110101 case SyntaxKind.AsteriskToken:
10102+ case SyntaxKind.AsteriskAsteriskToken:
1007210103 case SyntaxKind.AsteriskEqualsToken:
10104+ case SyntaxKind.AsteriskAsteriskEqualsToken:
1007310105 case SyntaxKind.SlashToken:
1007410106 case SyntaxKind.SlashEqualsToken:
1007510107 case SyntaxKind.PercentToken:
@@ -10088,7 +10120,7 @@ namespace ts {
1008810120 case SyntaxKind.CaretEqualsToken:
1008910121 case SyntaxKind.AmpersandToken:
1009010122 case SyntaxKind.AmpersandEqualsToken:
10091- // TypeScript 1.0 spec (April 2014): 4.15 .1
10123+ // TypeScript 1.0 spec (April 2014): 4.19 .1
1009210124 // These operators require their operands to be of type Any, the Number primitive type,
1009310125 // or an enum type. Operands of an enum type are treated
1009410126 // as having the primitive type Number. If one operand is the null or undefined value,
@@ -10117,7 +10149,7 @@ namespace ts {
1011710149 return numberType;
1011810150 case SyntaxKind.PlusToken:
1011910151 case SyntaxKind.PlusEqualsToken:
10120- // TypeScript 1.0 spec (April 2014): 4.15 .2
10152+ // TypeScript 1.0 spec (April 2014): 4.19 .2
1012110153 // The binary + operator requires both operands to be of the Number primitive type or an enum type,
1012210154 // or at least one of the operands to be of type Any or the String primitive type.
1012310155
@@ -11760,10 +11792,6 @@ namespace ts {
1176011792 checkSignatureDeclaration(node);
1176111793 let isAsync = isAsyncFunctionLike(node);
1176211794 if (isAsync) {
11763- if (!compilerOptions.experimentalAsyncFunctions) {
11764- error(node, Diagnostics.Experimental_support_for_async_functions_is_a_feature_that_is_subject_to_change_in_a_future_release_Specify_experimentalAsyncFunctions_to_remove_this_warning);
11765- }
11766-
1176711795 emitAwaiter = true;
1176811796 }
1176911797
@@ -13358,7 +13386,7 @@ namespace ts {
1335813386 }
1335913387
1336013388 // illegal case: forward reference
13361- if (!isDefinedBefore (propertyDecl, member)) {
13389+ if (!isBlockScopedNameDeclaredBeforeUse (propertyDecl, member)) {
1336213390 reportError = false;
1336313391 error(e, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums);
1336413392 return undefined;
0 commit comments