Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 120 additions & 5 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,8 @@ type Checker struct {
lastFlowNodeReachable bool
flowNodeReachable map[*ast.FlowNode]bool
flowNodePostSuper map[*ast.FlowNode]bool
potentialWeakMapSetCollisions []*ast.Node
potentialReflectCollisions []*ast.Node
renamedBindingElementsInTypes []*ast.Node
contextualInfos []ContextualInfo
inferenceContextInfos []InferenceContextInfo
Expand Down Expand Up @@ -2126,6 +2128,8 @@ func (c *Checker) checkSourceFile(ctx context.Context, sourceFile *ast.SourceFil
// Grammar checking
c.checkGrammarSourceFile(sourceFile)
c.renamedBindingElementsInTypes = nil
c.potentialWeakMapSetCollisions = nil
c.potentialReflectCollisions = nil
c.checkSourceElements(sourceFile.Statements.Nodes)
c.checkDeferredNodes(sourceFile)
if ast.IsExternalOrCommonJSModule(sourceFile) {
Expand All @@ -2143,6 +2147,18 @@ func (c *Checker) checkSourceFile(ctx context.Context, sourceFile *ast.SourceFil
} else {
c.wasCanceled = true
}
if len(c.potentialWeakMapSetCollisions) > 0 {
for _, node := range c.potentialWeakMapSetCollisions {
c.checkWeakMapSetCollision(node)
}
c.potentialWeakMapSetCollisions = nil
}
if len(c.potentialReflectCollisions) > 0 {
for _, node := range c.potentialReflectCollisions {
c.checkReflectCollision(node)
}
c.potentialReflectCollisions = nil
}
c.ctx = nil
links.typeChecked = true
}
Expand Down Expand Up @@ -2536,6 +2552,7 @@ func (c *Checker) checkPropertyDeclaration(node *ast.Node) {
c.checkGrammarComputedPropertyName(node.Name())
}
c.checkVariableLikeDeclaration(node)
c.setNodeLinksForPrivateIdentifierScope(node)
// property signatures already report "initializer not allowed in ambient context" elsewhere
if ast.HasSyntacticModifier(node, ast.ModifierFlagsAbstract) && ast.IsPropertyDeclaration(node) {
if node.Initializer() != nil {
Expand Down Expand Up @@ -2633,6 +2650,7 @@ func (c *Checker) checkMethodDeclaration(node *ast.Node) {
if ast.IsPrivateIdentifier(node.Name()) && ast.GetContainingClass(node) == nil {
c.error(node, diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies)
}
c.setNodeLinksForPrivateIdentifierScope(node)
}

func (c *Checker) checkClassStaticBlockDeclaration(node *ast.Node) {
Expand Down Expand Up @@ -2800,6 +2818,7 @@ func (c *Checker) checkAccessorDeclaration(node *ast.Node) {
c.checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType)
}
c.checkSourceElement(node.Body())
c.setNodeLinksForPrivateIdentifierScope(node)
}

func (c *Checker) checkTypeReferenceNode(node *ast.Node) {
Expand Down Expand Up @@ -10147,13 +10166,19 @@ func (c *Checker) assignBindingElementTypes(pattern *ast.Node, parentType *Type)
}

func (c *Checker) checkCollisionsForDeclarationName(node *ast.Node, name *ast.Node) {
c.checkCollisionWithRequireExportsInGeneratedCode(node, name)
switch {
case name == nil:
if name == nil {
return
case ast.IsClassLike(node):
}
c.checkCollisionWithRequireExportsInGeneratedCode(node, name)
c.checkCollisionWithGlobalPromiseInGeneratedCode(node, name)
c.recordPotentialCollisionWithWeakMapSetInGeneratedCode(node, name)
c.recordPotentialCollisionWithReflectInGeneratedCode(node, name)
if ast.IsClassLike(node) {
c.checkTypeNameIsReserved(name, diagnostics.Class_name_cannot_be_0)
case ast.IsEnumDeclaration(node):
if node.Flags&ast.NodeFlagsAmbient == 0 {
c.checkClassNameCollisionWithObject(name)
}
} else if ast.IsEnumDeclaration(node) {
c.checkTypeNameIsReserved(name, diagnostics.Enum_name_cannot_be_0)
}
}
Expand Down Expand Up @@ -10206,6 +10231,96 @@ func (c *Checker) needCollisionCheckForIdentifier(node *ast.Node, identifier *as
return true
}

func (c *Checker) setNodeLinksForPrivateIdentifierScope(node *ast.Node) {
if name := node.Name(); ast.IsPrivateIdentifier(name) {
// Check if we need to mark containers with the ContainsClassWithPrivateIdentifiers flag
// This happens for older language versions or when useDefineForClassFields is false
// PrivateNamesAndClassStaticBlocks is ES2022, ClassAndClassElementDecorators is ESNext
if c.languageVersion < core.ScriptTargetES2022 || c.languageVersion < core.ScriptTargetESNext || !c.emitStandardClassFields {
for lexicalScope := ast.GetEnclosingBlockScopeContainer(node); lexicalScope != nil; lexicalScope = ast.GetEnclosingBlockScopeContainer(lexicalScope) {
c.nodeLinks.Get(lexicalScope).flags |= NodeCheckFlagsContainsClassWithPrivateIdentifiers
}
}
}
}

func (c *Checker) recordPotentialCollisionWithWeakMapSetInGeneratedCode(node *ast.Node, name *ast.Node) {
if c.languageVersion <= core.ScriptTargetES2021 &&
(c.needCollisionCheckForIdentifier(node, name, "WeakMap") || c.needCollisionCheckForIdentifier(node, name, "WeakSet")) {
c.potentialWeakMapSetCollisions = append(c.potentialWeakMapSetCollisions, node)
}
}

func (c *Checker) checkWeakMapSetCollision(node *ast.Node) {
enclosingBlockScope := ast.GetEnclosingBlockScopeContainer(node)
if c.nodeLinks.Get(enclosingBlockScope).flags&NodeCheckFlagsContainsClassWithPrivateIdentifiers != 0 {
name := node.Name()
if name != nil && ast.IsIdentifier(name) {
c.errorSkippedOnNoEmit(node, diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, name.Text())
}
}
}

func (c *Checker) checkCollisionWithGlobalPromiseInGeneratedCode(node *ast.Node, name *ast.Node) {
if name == nil || c.languageVersion >= core.ScriptTargetES2017 || !c.needCollisionCheckForIdentifier(node, name, "Promise") {
return
}
// Uninstantiated modules shouldn't do this check
if ast.IsModuleDeclaration(node) && ast.GetModuleInstanceState(node) != ast.ModuleInstanceStateInstantiated {
return
}
// In case of variable declaration, node.parent is variable statement so look at the variable statement's parent
parent := ast.GetDeclarationContainer(node)
// Note: TypeScript checks for HasAsyncFunctions flag, but since that flag is not yet ported to Go,
// we conservatively check all external/CommonJS modules. This may produce false positives
// but is safer than missing real issues.
if ast.IsSourceFile(parent) && ast.IsExternalOrCommonJSModule(parent.AsSourceFile()) {
// If the declaration happens to be in external module, report error that Promise is a reserved identifier.
c.errorSkippedOnNoEmit(name, diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, scanner.DeclarationNameToString(name), scanner.DeclarationNameToString(name))
}
}

func (c *Checker) recordPotentialCollisionWithReflectInGeneratedCode(node *ast.Node, name *ast.Node) {
if name != nil && c.languageVersion <= core.ScriptTargetES2021 && c.needCollisionCheckForIdentifier(node, name, "Reflect") {
c.potentialReflectCollisions = append(c.potentialReflectCollisions, node)
}
}

func (c *Checker) checkReflectCollision(node *ast.Node) {
hasCollision := false
if ast.IsClassExpression(node) {
// ClassExpression names don't contribute to their containers, but do matter for any of their block-scoped members.
for _, member := range node.Members() {
if c.nodeLinks.Get(member).flags&NodeCheckFlagsContainsSuperPropertyInStaticInitializer != 0 {
hasCollision = true
break
}
}
} else if ast.IsFunctionExpression(node) {
// FunctionExpression names don't contribute to their containers, but do matter for their contents
if c.nodeLinks.Get(node).flags&NodeCheckFlagsContainsSuperPropertyInStaticInitializer != 0 {
hasCollision = true
}
} else {
container := ast.GetEnclosingBlockScopeContainer(node)
if container != nil && c.nodeLinks.Get(container).flags&NodeCheckFlagsContainsSuperPropertyInStaticInitializer != 0 {
hasCollision = true
}
}
if hasCollision {
name := node.Name()
if name != nil && ast.IsIdentifier(name) {
c.errorSkippedOnNoEmit(node, diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, scanner.DeclarationNameToString(name), "Reflect")
}
}
}

func (c *Checker) checkClassNameCollisionWithObject(name *ast.Node) {
if name.Text() == "Object" && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(name)) < core.ModuleKindES2015 {
c.error(name, diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_and_above_with_module_0, core.ModuleKind(c.moduleKind).String())
}
}

func (c *Checker) checkTypeOfExpression(node *ast.Node) *Type {
c.checkExpression(node.Expression())
return c.typeofType
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
checkForObjectTooStrict.ts(3,18): error TS2725: Class name cannot be 'Object' when targeting ES5 and above with module CommonJS.


==== checkForObjectTooStrict.ts (1 errors) ====
module Foo {

export class Object {
~~~~~~
!!! error TS2725: Class name cannot be 'Object' when targeting ES5 and above with module CommonJS.

}

}



class Bar extends Foo.Object { // should work

constructor () {

super();

}

}


class Baz extends Object {

constructor () { // ERROR, as expected

super();

}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
instanceofOperator.ts(7,11): error TS2725: Class name cannot be 'Object' when targeting ES5 and above with module CommonJS.
instanceofOperator.ts(12,5): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.
instanceofOperator.ts(15,20): error TS2359: The right-hand side of an 'instanceof' expression must be either of type 'any', a class, function, or other type assignable to the 'Function' interface type, or an object type with a 'Symbol.hasInstance' method.
instanceofOperator.ts(16,23): error TS2359: The right-hand side of an 'instanceof' expression must be either of type 'any', a class, function, or other type assignable to the 'Function' interface type, or an object type with a 'Symbol.hasInstance' method.
instanceofOperator.ts(19,5): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.
instanceofOperator.ts(21,5): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.


==== instanceofOperator.ts (5 errors) ====
==== instanceofOperator.ts (6 errors) ====
// Spec:
// The instanceof operator requires the left operand to be of type Any or an object type, and the right
// operand to be of type Any or a subtype of the ‘Function’ interface type. The result is always of the
// Boolean primitive type.

module test {
class Object { }
~~~~~~
!!! error TS2725: Class name cannot be 'Object' when targeting ES5 and above with module CommonJS.
var obj: Object;


Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
moduleInTypePosition1_0.ts(1,14): error TS2529: Duplicate identifier 'Promise'. Compiler reserves name 'Promise' in top level scope of a module containing async functions.
moduleInTypePosition1_1.ts(3,14): error TS2709: Cannot use namespace 'WinJS' as a type.


Expand All @@ -8,8 +9,10 @@ moduleInTypePosition1_1.ts(3,14): error TS2709: Cannot use namespace 'WinJS' as
~~~~~
!!! error TS2709: Cannot use namespace 'WinJS' as a type.

==== moduleInTypePosition1_0.ts (0 errors) ====
==== moduleInTypePosition1_0.ts (1 errors) ====
export class Promise {
~~~~~~~
!!! error TS2529: Duplicate identifier 'Promise'. Compiler reserves name 'Promise' in top level scope of a module containing async functions.
foo: string;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--- old.moduleInTypePosition1.errors.txt
+++ new.moduleInTypePosition1.errors.txt
@@= skipped -0, +0 lines =@@
+moduleInTypePosition1_0.ts(1,14): error TS2529: Duplicate identifier 'Promise'. Compiler reserves name 'Promise' in top level scope of a module containing async functions.
moduleInTypePosition1_1.ts(3,14): error TS2709: Cannot use namespace 'WinJS' as a type.


@@= skipped -7, +8 lines =@@
~~~~~
!!! error TS2709: Cannot use namespace 'WinJS' as a type.

-==== moduleInTypePosition1_0.ts (0 errors) ====
+==== moduleInTypePosition1_0.ts (1 errors) ====
export class Promise {
+ ~~~~~~~
+!!! error TS2529: Duplicate identifier 'Promise'. Compiler reserves name 'Promise' in top level scope of a module containing async functions.
foo: string;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
privateNameWeakMapCollision.ts(2,9): error TS18027: Compiler reserves name 'WeakMap' when emitting private identifier downlevel.
privateNameWeakMapCollision.ts(3,9): error TS18027: Compiler reserves name 'WeakSet' when emitting private identifier downlevel.


==== privateNameWeakMapCollision.ts (2 errors) ====
function test() {
let WeakMap;
~~~~~~~
!!! error TS18027: Compiler reserves name 'WeakMap' when emitting private identifier downlevel.
let WeakSet;
~~~~~~~
!!! error TS18027: Compiler reserves name 'WeakSet' when emitting private identifier downlevel.
class C {
#x;
}
}

This file was deleted.

Loading