@@ -517,16 +517,15 @@ namespace ts {
517517                const  isIIFE  =  containerFlags  &  ContainerFlags . IsFunctionExpression  &&  ! hasModifier ( node ,  ModifierFlags . Async )  &&  ! ! getImmediatelyInvokedFunctionExpression ( node ) ; 
518518                // A non-async IIFE is considered part of the containing control flow. Return statements behave 
519519                // similarly to break statements that exit to a label just past the statement body. 
520-                 if  ( isIIFE )  { 
521-                     currentReturnTarget  =  createBranchLabel ( ) ; 
522-                 } 
523-                 else  { 
520+                 if  ( ! isIIFE )  { 
524521                    currentFlow  =  {  flags : FlowFlags . Start  } ; 
525522                    if  ( containerFlags  &  ( ContainerFlags . IsFunctionExpression  |  ContainerFlags . IsObjectLiteralOrClassExpressionMethod ) )  { 
526523                        ( < FlowStart > currentFlow ) . container  =  < FunctionExpression  |  ArrowFunction  |  MethodDeclaration > node ; 
527524                    } 
528-                     currentReturnTarget  =  undefined ; 
529525                } 
526+                 // We create a return control flow graph for IIFEs and constructors. For constructors 
527+                 // we use the return control flow graph in strict property intialization checks. 
528+                 currentReturnTarget  =  isIIFE  ||  node . kind  ===  SyntaxKind . Constructor  ? createBranchLabel ( )  : undefined ; 
530529                currentBreakTarget  =  undefined ; 
531530                currentContinueTarget  =  undefined ; 
532531                activeLabels  =  undefined ; 
@@ -541,11 +540,14 @@ namespace ts {
541540                if  ( node . kind  ===  SyntaxKind . SourceFile )  { 
542541                    node . flags  |=  emitFlags ; 
543542                } 
544-                 if  ( isIIFE )  { 
543+                 if  ( currentReturnTarget )  { 
545544                    addAntecedent ( currentReturnTarget ,  currentFlow ) ; 
546545                    currentFlow  =  finishFlowLabel ( currentReturnTarget ) ; 
546+                     if  ( node . kind  ===  SyntaxKind . Constructor )  { 
547+                         ( < ConstructorDeclaration > node ) . returnFlowNode  =  currentFlow ; 
548+                     } 
547549                } 
548-                 else  { 
550+                 if   ( ! isIIFE )  { 
549551                    currentFlow  =  saveCurrentFlow ; 
550552                } 
551553                currentBreakTarget  =  saveBreakTarget ; 
@@ -2004,6 +2006,9 @@ namespace ts {
20042006                    if  ( currentFlow  &&  isNarrowableReference ( < Expression > node ) )  { 
20052007                        node . flowNode  =  currentFlow ; 
20062008                    } 
2009+                     if  ( isSpecialPropertyDeclaration ( node  as  PropertyAccessExpression ) )  { 
2010+                         bindSpecialPropertyDeclaration ( node  as  PropertyAccessExpression ) ; 
2011+                     } 
20072012                    break ; 
20082013                case  SyntaxKind . BinaryExpression :
20092014                    const  specialKind  =  getSpecialPropertyAssignmentKind ( node  as  BinaryExpression ) ; 
@@ -2312,7 +2317,7 @@ namespace ts {
23122317            declareSymbol ( file . symbol . exports ,  file . symbol ,  node ,  SymbolFlags . Property  |  SymbolFlags . ExportValue  |  SymbolFlags . ValueModule ,  SymbolFlags . None ) ; 
23132318        } 
23142319
2315-         function  bindThisPropertyAssignment ( node : BinaryExpression )  { 
2320+         function  bindThisPropertyAssignment ( node : BinaryExpression   |   PropertyAccessExpression )  { 
23162321            Debug . assert ( isInJavaScriptFile ( node ) ) ; 
23172322            const  container  =  getThisContainer ( node ,  /*includeArrowFunctions*/  false ) ; 
23182323            switch  ( container . kind )  { 
@@ -2338,8 +2343,19 @@ namespace ts {
23382343            } 
23392344        } 
23402345
2346+         function  bindSpecialPropertyDeclaration ( node : PropertyAccessExpression )  { 
2347+             Debug . assert ( isInJavaScriptFile ( node ) ) ; 
2348+             if  ( node . expression . kind  ===  SyntaxKind . ThisKeyword )  { 
2349+                 bindThisPropertyAssignment ( node ) ; 
2350+             } 
2351+             else  if  ( ( node . expression . kind  ===  SyntaxKind . Identifier  ||  node . expression . kind  ===  SyntaxKind . PropertyAccessExpression )  && 
2352+                 node . parent . parent . kind  ===  SyntaxKind . SourceFile )  { 
2353+                 bindStaticPropertyAssignment ( node ) ; 
2354+             } 
2355+         } 
2356+ 
23412357        function  bindPrototypePropertyAssignment ( node : BinaryExpression )  { 
2342-             // We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x was  a function. 
2358+             // We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x is  a function or class, or not declared . 
23432359
23442360            // Look up the function in the local scope, since prototype assignments should 
23452361            // follow the function declaration 
@@ -2355,24 +2371,27 @@ namespace ts {
23552371            bindPropertyAssignment ( constructorFunction . escapedText ,  leftSideOfAssignment ,  /*isPrototypeProperty*/  true ) ; 
23562372        } 
23572373
2358-         function  bindStaticPropertyAssignment ( node : BinaryExpression )  { 
2359-             // We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function. 
2360- 
2361-             // Look up the function in the local scope, since prototype assignments should 
2374+         /** 
2375+          * For nodes like `x.y = z`, declare a member 'y' on 'x' if x is a function or class, or not declared. 
2376+          * Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y; 
2377+          */ 
2378+         function  bindStaticPropertyAssignment ( node : BinaryExpression  |  PropertyAccessExpression )  { 
2379+             // Look up the function in the local scope, since static assignments should 
23622380            // follow the function declaration 
2363-             const  leftSideOfAssignment  =  node . left  as  PropertyAccessExpression ; 
2381+             const  leftSideOfAssignment  =  node . kind   ===   SyntaxKind . PropertyAccessExpression  ?  node  :  node . left  as  PropertyAccessExpression ; 
23642382            const  target  =  leftSideOfAssignment . expression ; 
23652383
23662384            if  ( isIdentifier ( target ) )  { 
23672385                // Fix up parent pointers since we're going to use these nodes before we bind into them 
2368-                 leftSideOfAssignment . parent  =  node ; 
23692386                target . parent  =  leftSideOfAssignment ; 
2370- 
2387+                 if  ( node . kind  ===  SyntaxKind . BinaryExpression )  { 
2388+                     leftSideOfAssignment . parent  =  node ; 
2389+                 } 
23712390                if  ( isNameOfExportsOrModuleExportsAliasDeclaration ( target ) )  { 
23722391                    // This can be an alias for the 'exports' or 'module.exports' names, e.g. 
23732392                    //    var util = module.exports; 
23742393                    //    util.property = function ... 
2375-                     bindExportsPropertyAssignment ( node ) ; 
2394+                     bindExportsPropertyAssignment ( node   as   BinaryExpression ) ; 
23762395                } 
23772396                else  { 
23782397                    bindPropertyAssignment ( target . escapedText ,  leftSideOfAssignment ,  /*isPrototypeProperty*/  false ) ; 
@@ -2381,17 +2400,41 @@ namespace ts {
23812400        } 
23822401
23832402        function  lookupSymbolForName ( name : __String )  { 
2384-             return  ( container . symbol  &&  container . symbol . exports  &&  container . symbol . exports . get ( name ) )  ||  ( container . locals  &&  container . locals . get ( name ) ) ; 
2403+             const  local  =  container . locals  &&  container . locals . get ( name ) ; 
2404+             if  ( local )  { 
2405+                 return  local . exportSymbol  ||  local ; 
2406+             } 
2407+             return  container . symbol  &&  container . symbol . exports  &&  container . symbol . exports . get ( name ) ; 
23852408        } 
23862409
2387-         function  bindPropertyAssignment ( functionName : __String ,  propertyAccessExpression : PropertyAccessExpression ,  isPrototypeProperty : boolean )  { 
2388-             let  targetSymbol  =  lookupSymbolForName ( functionName ) ; 
2389- 
2390-             if  ( targetSymbol  &&  isDeclarationOfFunctionOrClassExpression ( targetSymbol ) )  { 
2391-                 targetSymbol  =  ( targetSymbol . valueDeclaration  as  VariableDeclaration ) . initializer . symbol ; 
2410+         function  bindPropertyAssignment ( functionName : __String ,  propertyAccess : PropertyAccessExpression ,  isPrototypeProperty : boolean )  { 
2411+             const  symbol  =  lookupSymbolForName ( functionName ) ; 
2412+             let  targetSymbol  =  symbol  &&  isDeclarationOfFunctionOrClassExpression ( symbol )  ?
2413+                 ( symbol . valueDeclaration  as  VariableDeclaration ) . initializer . symbol  :
2414+                 symbol ; 
2415+             Debug . assert ( propertyAccess . parent . kind  ===  SyntaxKind . BinaryExpression  ||  propertyAccess . parent . kind  ===  SyntaxKind . ExpressionStatement ) ; 
2416+             let  isLegalPosition : boolean ; 
2417+             if  ( propertyAccess . parent . kind  ===  SyntaxKind . BinaryExpression )  { 
2418+                 const  initializerKind  =  ( propertyAccess . parent  as  BinaryExpression ) . right . kind ; 
2419+                 isLegalPosition  =  ( initializerKind  ===  SyntaxKind . ClassExpression  ||  initializerKind  ===  SyntaxKind . FunctionExpression )  && 
2420+                     propertyAccess . parent . parent . parent . kind  ===  SyntaxKind . SourceFile ; 
23922421            } 
2393- 
2394-             if  ( ! targetSymbol  ||  ! ( targetSymbol . flags  &  ( SymbolFlags . Function  |  SymbolFlags . Class ) ) )  { 
2422+             else  { 
2423+                 isLegalPosition  =  propertyAccess . parent . parent . kind  ===  SyntaxKind . SourceFile ; 
2424+             } 
2425+             if  ( ! isPrototypeProperty  &&  ( ! targetSymbol  ||  ! ( targetSymbol . flags  &  SymbolFlags . Namespace ) )  &&  isLegalPosition )  { 
2426+                 Debug . assert ( isIdentifier ( propertyAccess . expression ) ) ; 
2427+                 const  identifier  =  propertyAccess . expression  as  Identifier ; 
2428+                 const  flags  =   SymbolFlags . Module  |  SymbolFlags . JSContainer ; 
2429+                 const  excludeFlags  =  SymbolFlags . ValueModuleExcludes  &  ~ SymbolFlags . JSContainer ; 
2430+                 if  ( targetSymbol )  { 
2431+                     addDeclarationToSymbol ( symbol ,  identifier ,  flags ) ; 
2432+                 } 
2433+                 else  { 
2434+                     targetSymbol  =  declareSymbol ( container . locals ,  /*parent*/  undefined ,  identifier ,  flags ,  excludeFlags ) ; 
2435+                 } 
2436+             } 
2437+             if  ( ! targetSymbol  ||  ! ( targetSymbol . flags  &  ( SymbolFlags . Function  |  SymbolFlags . Class  |  SymbolFlags . NamespaceModule ) ) )  { 
23952438                return ; 
23962439            } 
23972440
@@ -2401,7 +2444,7 @@ namespace ts {
24012444                ( targetSymbol . exports  ||  ( targetSymbol . exports  =  createSymbolTable ( ) ) ) ; 
24022445
24032446            // Declare the method/property 
2404-             declareSymbol ( symbolTable ,  targetSymbol ,  propertyAccessExpression ,  SymbolFlags . Property ,  SymbolFlags . PropertyExcludes ) ; 
2447+             declareSymbol ( symbolTable ,  targetSymbol ,  propertyAccess ,  SymbolFlags . Property ,  SymbolFlags . PropertyExcludes ) ; 
24052448        } 
24062449
24072450        function  bindCallExpression ( node : CallExpression )  { 
0 commit comments