package checker import ( "fmt" "strings" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/jsnum" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath" ) func (c *Checker) grammarErrorOnFirstToken(node *ast.Node, message *diagnostics.Message, args ...any) bool { sourceFile := ast.GetSourceFileOfNode(node) if !c.hasParseDiagnostics(sourceFile) { span := scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) c.diagnostics.Add(ast.NewDiagnostic(sourceFile, span, message, args...)) return true } return false } func (c *Checker) grammarErrorAtPos(nodeForSourceFile *ast.Node, start int, length int, message *diagnostics.Message, args ...any) bool { sourceFile := ast.GetSourceFileOfNode(nodeForSourceFile) if !c.hasParseDiagnostics(sourceFile) { c.diagnostics.Add(ast.NewDiagnostic(sourceFile, core.NewTextRange(start, start+length), message, args...)) return true } return false } func (c *Checker) grammarErrorOnNode(node *ast.Node, message *diagnostics.Message, args ...any) bool { sourceFile := ast.GetSourceFileOfNode(node) if !c.hasParseDiagnostics(sourceFile) { c.error(node, message, args...) return true } return false } func (c *Checker) grammarErrorOnNodeSkippedOnNoEmit(node *ast.Node, message *diagnostics.Message, args ...any) bool { sourceFile := ast.GetSourceFileOfNode(node) if !c.hasParseDiagnostics(sourceFile) { d := NewDiagnosticForNode(node, message, args...) d.SetSkippedOnNoEmit() c.diagnostics.Add(d) return true } return false } func (c *Checker) checkGrammarRegularExpressionLiteral(_ *ast.RegularExpressionLiteral) bool { // !!! // Unclear if this is needed until regular expression parsing is more thoroughly implemented. return false // sourceFile := ast.GetSourceFileOfNode(node.AsNode()) // if !c.hasParseDiagnostics(sourceFile) && !node.IsUnterminated { // var lastError *ast.Diagnostic // scanner := NewScanner() // scanner.skipTrivia = true // scanner.SetScriptTarget(sourceFile.LanguageVersion) // scanner.SetLanguageVariant(sourceFile.LanguageVariant) // scanner.SetOnError(func(message *diagnostics.Message, start int, length int, args ...any) { // // !!! // // Original uses `tokenEnd()` - unclear if this is the same as the `start` passed in here. // // const start = scanner.TokenEnd() // // The scanner is operating on a slice of the original source text, so we need to adjust the start // // for error reporting. // start = start + node.Pos() // // For providing spelling suggestions // if message.Category() == diagnostics.CategoryMessage && lastError != nil && start == lastError.Pos() && length == lastError.Len() { // err := ast.NewDiagnostic(sourceFile, core.NewTextRange(start, start+length), message, args) // lastError.AddRelatedInfo(err) // } else if !(lastError != nil) || start != lastError.Pos() { // lastError = ast.NewDiagnostic(sourceFile, core.NewTextRange(start, start+length), message, args) // c.diagnostics.Add(lastError) // } // }) // scanner.SetText(sourceFile.Text[node.Pos():node.Loc.Len()]) // scanner.Scan() // if scanner.ReScanSlashToken() != ast.KindRegularExpressionLiteral { // panic("Expected to rescan RegularExpressionLiteral") // } // return lastError != nil // } // return false } func (c *Checker) checkGrammarPrivateIdentifierExpression(privId *ast.PrivateIdentifier) bool { privIdAsNode := privId.AsNode() if ast.GetContainingClass(privId.AsNode()) == nil { return c.grammarErrorOnNode(privId.AsNode(), diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies) } if !ast.IsForInStatement(privId.Parent) { if !ast.IsExpressionNode(privIdAsNode) { return c.grammarErrorOnNode(privIdAsNode, diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression) } isInOperation := ast.IsBinaryExpression(privId.Parent) && privId.Parent.AsBinaryExpression().OperatorToken.Kind == ast.KindInKeyword if c.getSymbolForPrivateIdentifierExpression(privIdAsNode) == nil && !isInOperation { return c.grammarErrorOnNode(privIdAsNode, diagnostics.Cannot_find_name_0, privId.Text) } } return false } func (c *Checker) checkGrammarMappedType(node *ast.MappedTypeNode) bool { if len(node.Members.Nodes) > 0 { return c.grammarErrorOnNode(node.Members.Nodes[0], diagnostics.A_mapped_type_may_not_declare_properties_or_methods) } return false } func (c *Checker) checkGrammarDecorator(decorator *ast.Decorator) bool { sourceFile := ast.GetSourceFileOfNode(decorator.AsNode()) if !c.hasParseDiagnostics(sourceFile) { node := decorator.Expression // DecoratorParenthesizedExpression : // `(` Expression `)` if ast.IsParenthesizedExpression(node) { return false } canHaveCallExpression := true var errorNode *ast.Node for { // Allow TS syntax such as non-null assertions and instantiation expressions if ast.IsExpressionWithTypeArguments(node) || ast.IsNonNullExpression(node) { node = node.Expression() continue } // DecoratorCallExpression : // DecoratorMemberExpression Arguments if ast.IsCallExpression(node) { callExpr := node.AsCallExpression() if !canHaveCallExpression { errorNode = node } if callExpr.QuestionDotToken != nil { // Even if we already have an error node, error at the `?.` token since it appears earlier. errorNode = callExpr.QuestionDotToken } node = callExpr.Expression canHaveCallExpression = false continue } // DecoratorMemberExpression : // IdentifierReference // DecoratorMemberExpression `.` IdentifierName // DecoratorMemberExpression `.` PrivateIdentifier if ast.IsPropertyAccessExpression(node) { propertyAccessExpr := node.AsPropertyAccessExpression() if propertyAccessExpr.QuestionDotToken != nil { // Even if we already have an error node, error at the `?.` token since it appears earlier. errorNode = propertyAccessExpr.QuestionDotToken } node = propertyAccessExpr.Expression canHaveCallExpression = false continue } if !ast.IsIdentifier(node) { // Even if we already have an error node, error at this node since it appears earlier. errorNode = node } break } if errorNode != nil { err := c.error(decorator.Expression, diagnostics.Expression_must_be_enclosed_in_parentheses_to_be_used_as_a_decorator) err.AddRelatedInfo(createDiagnosticForNode(errorNode, diagnostics.Invalid_syntax_in_decorator)) return true } } return false } func (c *Checker) checkGrammarExportDeclaration(node *ast.ExportDeclaration) bool { if node.IsTypeOnly && node.ExportClause != nil && node.ExportClause.Kind == ast.KindNamedExports { return c.checkGrammarTypeOnlyNamedImportsOrExports(node.ExportClause) } return false } func (c *Checker) checkGrammarModuleElementContext(node *ast.Statement, errorMessage *diagnostics.Message) bool { isInAppropriateContext := node.Parent.Kind == ast.KindSourceFile || node.Parent.Kind == ast.KindModuleBlock || node.Parent.Kind == ast.KindModuleDeclaration if !isInAppropriateContext { c.grammarErrorOnFirstToken(node, errorMessage) } return !isInAppropriateContext } func (c *Checker) checkGrammarModifiers(node *ast.Node /*Union[HasModifiers, HasDecorators, HasIllegalModifiers, HasIllegalDecorators]*/) bool { if node.Modifiers() == nil { return false } if c.reportObviousDecoratorErrors(node) || c.reportObviousModifierErrors(node) { return true } if ast.IsParameter(node) && ast.IsThisParameter(node) { return c.grammarErrorOnFirstToken(node, diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters) } blockScopeKind := ast.NodeFlagsNone if ast.IsVariableStatement(node) { blockScopeKind = node.AsVariableStatement().DeclarationList.Flags & ast.NodeFlagsBlockScoped } var lastStatic *ast.Node var lastDeclare *ast.Node var lastAsync *ast.Node var lastOverride *ast.Node var firstDecorator *ast.Node flags := ast.ModifierFlagsNone sawExportBeforeDecorators := false // We parse decorators and modifiers in four contiguous chunks: // [...leadingDecorators, ...leadingModifiers, ...trailingDecorators, ...trailingModifiers]. It is an error to // have both leading and trailing decorators. hasLeadingDecorators := false var modifiers []*ast.Node if node.Modifiers() != nil { modifiers = node.Modifiers().Nodes } for _, modifier := range modifiers { if ast.IsDecorator(modifier) { if !nodeCanBeDecorated(c.legacyDecorators, node, node.Parent, node.Parent.Parent) { if node.Kind == ast.KindMethodDeclaration && !ast.NodeIsPresent(node.Body()) { return c.grammarErrorOnFirstToken(node, diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload) } else { return c.grammarErrorOnFirstToken(node, diagnostics.Decorators_are_not_valid_here) } } else if c.legacyDecorators && (node.Kind == ast.KindGetAccessor || node.Kind == ast.KindSetAccessor) { accessors := c.getAllAccessorDeclarationsForDeclaration(node) if ast.HasDecorators(accessors.firstAccessor) && node == accessors.secondAccessor { return c.grammarErrorOnFirstToken(node, diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name) } } // if we've seen any modifiers aside from `export`, `default`, or another decorator, then this is an invalid position if flags&^(ast.ModifierFlagsExportDefault|ast.ModifierFlagsDecorator) != 0 { return c.grammarErrorOnNode(modifier, diagnostics.Decorators_are_not_valid_here) } // if we've already seen leading decorators and leading modifiers, then trailing decorators are an invalid position if hasLeadingDecorators && flags&ast.ModifierFlagsModifier != 0 { if firstDecorator == nil { panic("Expected firstDecorator to be set") } sourceFile := ast.GetSourceFileOfNode(modifier) if !c.hasParseDiagnostics(sourceFile) { err := c.error(modifier, diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export) err.AddRelatedInfo(createDiagnosticForNode(firstDecorator, diagnostics.Decorator_used_before_export_here)) return true } return false } flags |= ast.ModifierFlagsDecorator // if we have not yet seen a modifier, then these are leading decorators if flags&ast.ModifierFlagsModifier == 0 { hasLeadingDecorators = true } else if flags&ast.ModifierFlagsExport != 0 { sawExportBeforeDecorators = true } if firstDecorator == nil { firstDecorator = modifier } } else { if modifier.Kind != ast.KindReadonlyKeyword { if node.Kind == ast.KindPropertySignature || node.Kind == ast.KindMethodSignature { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_type_member, scanner.TokenToString(modifier.Kind)) } if node.Kind == ast.KindIndexSignature && (modifier.Kind != ast.KindStaticKeyword || !ast.IsClassLike(node.Parent)) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_an_index_signature, scanner.TokenToString(modifier.Kind)) } } if modifier.Kind != ast.KindInKeyword && modifier.Kind != ast.KindOutKeyword && modifier.Kind != ast.KindConstKeyword { if node.Kind == ast.KindTypeParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_type_parameter, scanner.TokenToString(modifier.Kind)) } } switch modifier.Kind { case ast.KindConstKeyword: if node.Kind != ast.KindEnumDeclaration && node.Kind != ast.KindTypeParameter { return c.grammarErrorOnNode(node, diagnostics.A_class_member_cannot_have_the_0_keyword, scanner.TokenToString(ast.KindConstKeyword)) } // !!! // parent := (isJSDocTemplateTag(node.Parent) && getEffectiveJSDocHost(node.Parent)) || node.Parent parent := node.Parent if node.Kind == ast.KindTypeParameter { if !(ast.IsFunctionLikeDeclaration(parent) || ast.IsClassLike(parent) || ast.IsFunctionTypeNode(parent) || ast.IsConstructorTypeNode(parent) || ast.IsCallSignatureDeclaration(parent) || ast.IsConstructSignatureDeclaration(parent) || ast.IsMethodSignatureDeclaration(parent)) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, scanner.TokenToString(modifier.Kind)) } } case ast.KindOverrideKeyword: // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. if flags&ast.ModifierFlagsOverride != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "override") } else if flags&ast.ModifierFlagsAmbient != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "override", "declare") } else if flags&ast.ModifierFlagsReadonly != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "override", "readonly") } else if flags&ast.ModifierFlagsAccessor != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "override", "accessor") } else if flags&ast.ModifierFlagsAsync != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "override", "async") } flags |= ast.ModifierFlagsOverride lastOverride = modifier case ast.KindPublicKeyword, ast.KindProtectedKeyword, ast.KindPrivateKeyword: text := visibilityToString(ast.ModifierToFlag(modifier.Kind)) if flags&ast.ModifierFlagsAccessibilityModifier != 0 { return c.grammarErrorOnNode(modifier, diagnostics.Accessibility_modifier_already_seen) } else if flags&ast.ModifierFlagsOverride != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "override") } else if flags&ast.ModifierFlagsStatic != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "static") } else if flags&ast.ModifierFlagsAccessor != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "accessor") } else if flags&ast.ModifierFlagsReadonly != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "readonly") } else if flags&ast.ModifierFlagsAsync != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "async") } else if node.Parent.Kind == ast.KindModuleBlock || node.Parent.Kind == ast.KindSourceFile { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_module_or_namespace_element, text) } else if flags&ast.ModifierFlagsAbstract != 0 { if modifier.Kind == ast.KindPrivateKeyword { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, text, "abstract") } else if modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, text, "abstract") } } else if ast.IsPrivateIdentifierClassElementDeclaration(node) { return c.grammarErrorOnNode(modifier, diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier) } flags |= ast.ModifierToFlag(modifier.Kind) case ast.KindStaticKeyword: if flags&ast.ModifierFlagsStatic != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "static") } else if flags&ast.ModifierFlagsReadonly != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "static", "readonly") } else if flags&ast.ModifierFlagsAsync != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "static", "async") } else if flags&ast.ModifierFlagsAccessor != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "static", "accessor") } else if node.Parent.Kind == ast.KindModuleBlock || node.Parent.Kind == ast.KindSourceFile { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_module_or_namespace_element, "static") } else if node.Kind == ast.KindParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_parameter, "static") } else if flags&ast.ModifierFlagsAbstract != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "static", "abstract") } else if flags&ast.ModifierFlagsOverride != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "static", "override") } flags |= ast.ModifierFlagsStatic lastStatic = modifier case ast.KindAccessorKeyword: if flags&ast.ModifierFlagsAccessor != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "accessor") } else if flags&ast.ModifierFlagsReadonly != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "accessor", "readonly") } else if flags&ast.ModifierFlagsAmbient != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "accessor", "declare") } else if node.Kind != ast.KindPropertyDeclaration { return c.grammarErrorOnNode(modifier, diagnostics.X_accessor_modifier_can_only_appear_on_a_property_declaration) } flags |= ast.ModifierFlagsAccessor case ast.KindReadonlyKeyword: if flags&ast.ModifierFlagsReadonly != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "readonly") } else if node.Kind != ast.KindPropertyDeclaration && node.Kind != ast.KindPropertySignature && node.Kind != ast.KindIndexSignature && node.Kind != ast.KindParameter { // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. return c.grammarErrorOnNode(modifier, diagnostics.X_readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature) } else if flags&ast.ModifierFlagsAccessor != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "readonly", "accessor") } flags |= ast.ModifierFlagsReadonly case ast.KindExportKeyword: if c.compilerOptions.VerbatimModuleSyntax == core.TSTrue && node.Flags&ast.NodeFlagsAmbient == 0 && node.Kind != ast.KindTypeAliasDeclaration && node.Kind != ast.KindInterfaceDeclaration && node.Kind != ast.KindModuleDeclaration && node.Parent.Kind == ast.KindSourceFile && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node)) == core.ModuleKindCommonJS { return c.grammarErrorOnNode(modifier, diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled) } if flags&ast.ModifierFlagsExport != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "export") } else if flags&ast.ModifierFlagsAmbient != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "declare") } else if flags&ast.ModifierFlagsAbstract != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "abstract") } else if flags&ast.ModifierFlagsAsync != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "async") } else if ast.IsClassLike(node.Parent) && !ast.IsJSTypeAliasDeclaration(node) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_class_elements_of_this_kind, "export") } else if node.Kind == ast.KindParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_parameter, "export") } else if blockScopeKind == ast.NodeFlagsUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_using_declaration, "export") } else if blockScopeKind == ast.NodeFlagsAwaitUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_an_await_using_declaration, "export") } flags |= ast.ModifierFlagsExport case ast.KindDefaultKeyword: var container *ast.Node if node.Parent.Kind == ast.KindSourceFile { container = node.Parent } else { container = node.Parent.Parent } if container.Kind == ast.KindModuleDeclaration && !ast.IsAmbientModule(container) { return c.grammarErrorOnNode(modifier, diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module) } else if blockScopeKind == ast.NodeFlagsUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_using_declaration, "default") } else if blockScopeKind == ast.NodeFlagsAwaitUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_an_await_using_declaration, "default") } else if flags&ast.ModifierFlagsExport == 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "default") } else if sawExportBeforeDecorators { return c.grammarErrorOnNode(firstDecorator, diagnostics.Decorators_are_not_valid_here) } flags |= ast.ModifierFlagsDefault case ast.KindDeclareKeyword: if flags&ast.ModifierFlagsAmbient != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "declare") } else if flags&ast.ModifierFlagsAsync != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_in_an_ambient_context, "async") } else if flags&ast.ModifierFlagsOverride != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_in_an_ambient_context, "override") } else if ast.IsClassLike(node.Parent) && !ast.IsPropertyDeclaration(node) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_class_elements_of_this_kind, "declare") } else if node.Kind == ast.KindParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_parameter, "declare") } else if blockScopeKind == ast.NodeFlagsUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_using_declaration, "declare") } else if blockScopeKind == ast.NodeFlagsAwaitUsing { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_an_await_using_declaration, "declare") } else if (node.Parent.Flags&ast.NodeFlagsAmbient != 0) && node.Parent.Kind == ast.KindModuleBlock { return c.grammarErrorOnNode(modifier, diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context) } else if ast.IsPrivateIdentifierClassElementDeclaration(node) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_a_private_identifier, "declare") } else if flags&ast.ModifierFlagsAccessor != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "declare", "accessor") } flags |= ast.ModifierFlagsAmbient lastDeclare = modifier case ast.KindAbstractKeyword: if flags&ast.ModifierFlagsAbstract != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "abstract") } if node.Kind != ast.KindClassDeclaration && node.Kind != ast.KindConstructorType { if node.Kind != ast.KindMethodDeclaration && node.Kind != ast.KindPropertyDeclaration && node.Kind != ast.KindGetAccessor && node.Kind != ast.KindSetAccessor { return c.grammarErrorOnNode(modifier, diagnostics.X_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration) } if !(node.Parent.Kind == ast.KindClassDeclaration && ast.HasSyntacticModifier(node.Parent, ast.ModifierFlagsAbstract)) { var message *diagnostics.Message if node.Kind == ast.KindPropertyDeclaration { message = diagnostics.Abstract_properties_can_only_appear_within_an_abstract_class } else { message = diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class } return c.grammarErrorOnNode(modifier, message) } if flags&ast.ModifierFlagsStatic != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "static", "abstract") } if flags&ast.ModifierFlagsPrivate != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "private", "abstract") } if flags&ast.ModifierFlagsAsync != 0 && lastAsync != nil { return c.grammarErrorOnNode(lastAsync, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "async", "abstract") } if flags&ast.ModifierFlagsOverride != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "abstract", "override") } if flags&ast.ModifierFlagsAccessor != 0 && modifier.Flags&ast.NodeFlagsReparsed == 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "abstract", "accessor") } } if name := node.Name(); name != nil && name.Kind == ast.KindPrivateIdentifier { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_a_private_identifier, "abstract") } flags |= ast.ModifierFlagsAbstract case ast.KindAsyncKeyword: if flags&ast.ModifierFlagsAsync != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, "async") } else if flags&ast.ModifierFlagsAmbient != 0 || node.Parent.Flags&ast.NodeFlagsAmbient != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_in_an_ambient_context, "async") } else if node.Kind == ast.KindParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_parameter, "async") } if flags&ast.ModifierFlagsAbstract != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_be_used_with_1_modifier, "async", "abstract") } flags |= ast.ModifierFlagsAsync lastAsync = modifier case ast.KindInKeyword, ast.KindOutKeyword: var inOutFlag ast.ModifierFlags if modifier.Kind == ast.KindInKeyword { inOutFlag = ast.ModifierFlagsIn } else { inOutFlag = ast.ModifierFlagsOut } var inOutText string if modifier.Kind == ast.KindInKeyword { inOutText = "in" } else { inOutText = "out" } // !!! // parent := isJSDocTemplateTag(node.Parent) && (getEffectiveJSDocHost(node.Parent) || core.Find(getJSDocRoot(node.Parent). /* ? */ tags, isJSDocTypedefTag)) || node.Parent parent := node.Parent if node.Kind != ast.KindTypeParameter || parent != nil && !(ast.IsInterfaceDeclaration(parent) || ast.IsClassLike(parent) || ast.IsTypeAliasDeclaration(parent) || isJSDocTypedefTag(parent)) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText) } if flags&inOutFlag != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_already_seen, inOutText) } if inOutFlag&ast.ModifierFlagsIn != 0 && flags&ast.ModifierFlagsOut != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "in", "out") } flags |= inOutFlag } } } if node.Kind == ast.KindConstructor { if flags&ast.ModifierFlagsStatic != 0 { return c.grammarErrorOnNode(lastStatic, diagnostics.X_0_modifier_cannot_appear_on_a_constructor_declaration, "static") } if flags&ast.ModifierFlagsOverride != 0 { return c.grammarErrorOnNode(lastOverride, diagnostics.X_0_modifier_cannot_appear_on_a_constructor_declaration, "override") } if flags&ast.ModifierFlagsAsync != 0 { return c.grammarErrorOnNode(lastAsync, diagnostics.X_0_modifier_cannot_appear_on_a_constructor_declaration, "async") } return false } else if (node.Kind == ast.KindImportDeclaration || node.Kind == ast.KindJSImportDeclaration || node.Kind == ast.KindImportEqualsDeclaration) && flags&ast.ModifierFlagsAmbient != 0 { return c.grammarErrorOnNode(lastDeclare, diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare") } else if node.Kind == ast.KindParameter && (flags&ast.ModifierFlagsParameterPropertyModifier != 0) && ast.IsBindingPattern(node.Name()) { return c.grammarErrorOnNode(node, diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern) } else if node.Kind == ast.KindParameter && (flags&ast.ModifierFlagsParameterPropertyModifier != 0) && node.AsParameterDeclaration().DotDotDotToken != nil { return c.grammarErrorOnNode(node, diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter) } if flags&ast.ModifierFlagsAsync != 0 { return c.checkGrammarAsyncModifier(node, lastAsync) } return false } func isJSDocTypedefTag(_ *ast.Node) bool { // !!! return false } func (c *Checker) reportObviousModifierErrors(node *ast.Node) bool { modifier := c.findFirstIllegalModifier(node) if modifier == nil { return false } return c.grammarErrorOnFirstToken(modifier, diagnostics.Modifiers_cannot_appear_here) } func (c *Checker) findFirstModifierExcept(node *ast.Node, allowedModifier ast.Kind) *ast.Node { modifiers := node.Modifiers() if modifiers == nil { return nil } modifier := core.Find(modifiers.Nodes, ast.IsModifier) if modifier != nil && modifier.Kind != allowedModifier { return modifier } else { return nil } } func (c *Checker) findFirstIllegalModifier(node *ast.Node) *ast.Node { switch node.Kind { case ast.KindGetAccessor, ast.KindSetAccessor, ast.KindConstructor, ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindIndexSignature, ast.KindModuleDeclaration, ast.KindImportDeclaration, ast.KindJSImportDeclaration, ast.KindImportEqualsDeclaration, ast.KindExportDeclaration, ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindParameter, ast.KindTypeParameter, ast.KindJSTypeAliasDeclaration: return nil case ast.KindClassStaticBlockDeclaration, ast.KindPropertyAssignment, ast.KindShorthandPropertyAssignment, ast.KindNamespaceExportDeclaration, ast.KindMissingDeclaration: if modifiers := node.Modifiers(); modifiers != nil { return core.Find(modifiers.Nodes, ast.IsModifier) } return nil default: if node.Parent.Kind == ast.KindModuleBlock || node.Parent.Kind == ast.KindSourceFile { return nil } switch node.Kind { case ast.KindFunctionDeclaration: return c.findFirstModifierExcept(node, ast.KindAsyncKeyword) case ast.KindClassDeclaration, ast.KindConstructorType: return c.findFirstModifierExcept(node, ast.KindAbstractKeyword) case ast.KindClassExpression, ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration: if modifiers := node.Modifiers(); modifiers != nil { return core.Find(modifiers.Nodes, ast.IsModifier) } return nil case ast.KindVariableStatement: if node.AsVariableStatement().DeclarationList.Flags&ast.NodeFlagsUsing != 0 { return c.findFirstModifierExcept(node, ast.KindAwaitKeyword) } else if modifiers := node.Modifiers(); modifiers != nil { return core.Find(modifiers.Nodes, ast.IsModifier) } return nil case ast.KindEnumDeclaration: return c.findFirstModifierExcept(node, ast.KindConstKeyword) default: panic("Unhandled case in findFirstIllegalModifier.") } } } func (c *Checker) reportObviousDecoratorErrors(node *ast.Node) bool { decorator := c.findFirstIllegalDecorator(node) if decorator == nil { return false } return c.grammarErrorOnFirstToken(decorator, diagnostics.Decorators_are_not_valid_here) } func (c *Checker) findFirstIllegalDecorator(node *ast.Node) *ast.Node { if ast.CanHaveIllegalDecorators(node) { decorator := core.Find(node.Modifiers().Nodes, ast.IsDecorator) return decorator } else { return nil } } func (c *Checker) checkGrammarAsyncModifier(node *ast.Node, asyncModifier *ast.Node) bool { switch node.Kind { case ast.KindMethodDeclaration, ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction: return false } return c.grammarErrorOnNode(asyncModifier, diagnostics.X_0_modifier_cannot_be_used_here, "async") } func (c *Checker) checkGrammarForDisallowedTrailingComma(list *ast.NodeList, diag *diagnostics.Message) bool { if list != nil && list.HasTrailingComma() { return c.grammarErrorAtPos(list.Nodes[0], list.End()-len(","), len(","), diag) } return false } func (c *Checker) checkGrammarTypeParameterList(typeParameters *ast.NodeList, file *ast.SourceFile) bool { if typeParameters != nil && len(typeParameters.Nodes) == 0 { start := typeParameters.Pos() - len("<") end := scanner.SkipTrivia(file.Text(), typeParameters.End()) + len(">") return c.grammarErrorAtPos(file.AsNode(), start, end-start, diagnostics.Type_parameter_list_cannot_be_empty) } return false } func (c *Checker) checkGrammarParameterList(parameters *ast.NodeList) bool { seenOptionalParameter := false parameterCount := len(parameters.Nodes) for i := range parameterCount { parameter := parameters.Nodes[i].AsParameterDeclaration() if parameter.DotDotDotToken != nil { if i != parameterCount-1 { return c.grammarErrorOnNode(parameter.DotDotDotToken, diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list) } if parameter.Flags&ast.NodeFlagsAmbient == 0 { c.checkGrammarForDisallowedTrailingComma(parameters, diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma) } if parameter.QuestionToken != nil { return c.grammarErrorOnNode(parameter.QuestionToken, diagnostics.A_rest_parameter_cannot_be_optional) } if parameter.Initializer != nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.A_rest_parameter_cannot_have_an_initializer) } } else if isOptionalDeclaration(parameter.AsNode()) { // !!! // used to be hasEffectiveQuestionToken for JSDoc seenOptionalParameter = true if parameter.QuestionToken != nil && parameter.Initializer != nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.Parameter_cannot_have_question_mark_and_initializer) } } else if seenOptionalParameter && parameter.Initializer == nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.A_required_parameter_cannot_follow_an_optional_parameter) } } return false } func (c *Checker) checkGrammarForUseStrictSimpleParameterList(node *ast.Node) bool { if c.languageVersion >= core.ScriptTargetES2016 { body := node.Body() var useStrictDirective *ast.Node if body != nil && ast.IsBlock(body) { useStrictDirective = binder.FindUseStrictPrologue(ast.GetSourceFileOfNode(node), body.AsBlock().Statements.Nodes) } if useStrictDirective != nil { nonSimpleParameters := core.Filter(node.Parameters(), func(n *ast.Node) bool { parameter := n.AsParameterDeclaration() return parameter.Initializer != nil || ast.IsBindingPattern(parameter.Name()) || isRestParameter(parameter.AsNode()) }) if len(nonSimpleParameters) != 0 { for _, parameter := range nonSimpleParameters { err := c.error(parameter, diagnostics.This_parameter_is_not_allowed_with_use_strict_directive) err.AddRelatedInfo(createDiagnosticForNode(useStrictDirective, diagnostics.X_use_strict_directive_used_here)) } err := c.error(useStrictDirective, diagnostics.X_use_strict_directive_cannot_be_used_with_non_simple_parameter_list) for index, parameter := range nonSimpleParameters { var relatedMessage *diagnostics.Message if index == 0 { relatedMessage = diagnostics.Non_simple_parameter_declared_here } else { relatedMessage = diagnostics.X_and_here } err.AddRelatedInfo(createDiagnosticForNode(parameter, relatedMessage)) } return true } } } return false } func (c *Checker) checkGrammarFunctionLikeDeclaration(node *ast.Node) bool { // Prevent cascading error by short-circuit file := ast.GetSourceFileOfNode(node) funcData := node.FunctionLikeData() return c.checkGrammarModifiers(node) || c.checkGrammarTypeParameterList(funcData.TypeParameters, file) || c.checkGrammarParameterList(funcData.Parameters) || c.checkGrammarArrowFunction(node, file) || (ast.IsFunctionLikeDeclaration(node) && c.checkGrammarForUseStrictSimpleParameterList(node)) } func (c *Checker) checkGrammarClassLikeDeclaration(node *ast.Node) bool { file := ast.GetSourceFileOfNode(node) return c.checkGrammarClassDeclarationHeritageClauses(node, file) || c.checkGrammarTypeParameterList(node.ClassLikeData().TypeParameters, file) } func (c *Checker) checkGrammarArrowFunction(node *ast.Node, file *ast.SourceFile) bool { if !ast.IsArrowFunction(node) { return false } arrowFunc := node.AsArrowFunction() typeParameters := arrowFunc.TypeParameters if typeParameters != nil { typeParamNodes := typeParameters.Nodes if len(typeParamNodes) == 0 || len(typeParamNodes) == 1 && typeParamNodes[0].AsTypeParameter().Constraint == nil || typeParameters.HasTrailingComma() { if tspath.FileExtensionIsOneOf(file.FileName(), []string{tspath.ExtensionMts, tspath.ExtensionCts}) { // TODO(danielr): should we return early here? c.grammarErrorOnNode(typeParameters.Nodes[0], diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint) } } } equalsGreaterThanToken := arrowFunc.EqualsGreaterThanToken startLine, _ := scanner.GetECMALineAndCharacterOfPosition(file, equalsGreaterThanToken.Pos()) endLine, _ := scanner.GetECMALineAndCharacterOfPosition(file, equalsGreaterThanToken.End()) return startLine != endLine && c.grammarErrorOnNode(equalsGreaterThanToken, diagnostics.Line_terminator_not_permitted_before_arrow) } func (c *Checker) checkGrammarIndexSignatureParameters(node *ast.IndexSignatureDeclaration) bool { paramNodes := node.Parameters.Nodes if len(paramNodes) == 0 { return c.grammarErrorOnNode(node.AsNode(), diagnostics.An_index_signature_must_have_exactly_one_parameter) } parameter := paramNodes[0].AsParameterDeclaration() if len(paramNodes) != 1 { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_must_have_exactly_one_parameter) } c.checkGrammarForDisallowedTrailingComma(node.Parameters, diagnostics.An_index_signature_cannot_have_a_trailing_comma) if parameter.DotDotDotToken != nil { return c.grammarErrorOnNode(parameter.DotDotDotToken, diagnostics.An_index_signature_cannot_have_a_rest_parameter) } if parameter.Modifiers() != nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier) } if parameter.QuestionToken != nil { return c.grammarErrorOnNode(parameter.QuestionToken, diagnostics.An_index_signature_parameter_cannot_have_a_question_mark) } if parameter.Initializer != nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_parameter_cannot_have_an_initializer) } typeNode := parameter.Type if typeNode == nil { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_parameter_must_have_a_type_annotation) } t := c.getTypeFromTypeNode(typeNode) if someType(t, func(t *Type) bool { return t.flags&TypeFlagsStringOrNumberLiteralOrUnique != 0 }) || c.isGenericType(t) { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead) } if !everyType(t, c.isValidIndexKeyType) { return c.grammarErrorOnNode(parameter.Name(), diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type) } if node.Type == nil { return c.grammarErrorOnNode(node.AsNode(), diagnostics.An_index_signature_must_have_a_type_annotation) } return false } func (c *Checker) checkGrammarIndexSignature(node *ast.IndexSignatureDeclaration) bool { // Prevent cascading error by short-circuit return c.checkGrammarModifiers(node.AsNode()) || c.checkGrammarIndexSignatureParameters(node) } func (c *Checker) checkGrammarForAtLeastOneTypeArgument(node *ast.Node, typeArguments *ast.NodeList) bool { if typeArguments != nil && len(typeArguments.Nodes) == 0 { sourceFile := ast.GetSourceFileOfNode(node) start := typeArguments.Pos() - len("<") end := scanner.SkipTrivia(sourceFile.Text(), typeArguments.End()) + len(">") return c.grammarErrorAtPos(sourceFile.AsNode(), start, end-start, diagnostics.Type_argument_list_cannot_be_empty) } return false } func (c *Checker) checkGrammarTypeArguments(node *ast.Node, typeArguments *ast.NodeList) bool { return c.checkGrammarForDisallowedTrailingComma(typeArguments, diagnostics.Trailing_comma_not_allowed) || c.checkGrammarForAtLeastOneTypeArgument(node, typeArguments) } func (c *Checker) checkGrammarTaggedTemplateChain(node *ast.TaggedTemplateExpression) bool { if node.QuestionDotToken != nil || node.Flags&ast.NodeFlagsOptionalChain != 0 { return c.grammarErrorOnNode(node.Template, diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain) } return false } func (c *Checker) checkGrammarHeritageClause(node *ast.HeritageClause) bool { types := node.Types if c.checkGrammarForDisallowedTrailingComma(types, diagnostics.Trailing_comma_not_allowed) { return true } if types != nil && len(types.Nodes) == 0 { listType := scanner.TokenToString(node.Token) // TODO(danielr): why not error on the token? return c.grammarErrorAtPos(node.AsNode(), types.Pos(), 0, diagnostics.X_0_list_cannot_be_empty, listType) } for _, node := range types.Nodes { if c.checkGrammarExpressionWithTypeArguments(node) { return true } } return false } func (c *Checker) checkGrammarExpressionWithTypeArguments(node *ast.Node /*Union[ExpressionWithTypeArguments, TypeQueryNode]*/) bool { if !ast.IsExpressionWithTypeArguments(node) { return false } exprWithTypeArgs := node.AsExpressionWithTypeArguments() if node.Expression().Kind == ast.KindImportKeyword && exprWithTypeArgs.TypeArguments != nil { return c.grammarErrorOnNode(node, diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments) } return c.checkGrammarTypeArguments(node, exprWithTypeArgs.TypeArguments) } func (c *Checker) checkGrammarClassDeclarationHeritageClauses(node *ast.ClassLikeDeclaration, file *ast.SourceFile) bool { seenExtendsClause := false seenImplementsClause := false classLikeData := node.ClassLikeData() if !c.checkGrammarModifiers(node) && classLikeData.HeritageClauses != nil { for _, heritageClauseNode := range classLikeData.HeritageClauses.Nodes { heritageClause := heritageClauseNode.AsHeritageClause() if heritageClause.Token == ast.KindExtendsKeyword { if seenExtendsClause { return c.grammarErrorOnFirstToken(heritageClauseNode, diagnostics.X_extends_clause_already_seen) } if seenImplementsClause { return c.grammarErrorOnFirstToken(heritageClauseNode, diagnostics.X_extends_clause_must_precede_implements_clause) } typeNodes := heritageClause.Types.Nodes if len(typeNodes) > 1 { return c.grammarErrorOnFirstToken(typeNodes[1], diagnostics.Classes_can_only_extend_a_single_class) } for _, j := range node.JSDoc(file) { if j.AsJSDoc().Tags == nil { continue } for _, tag := range j.AsJSDoc().Tags.Nodes { if tag.Kind == ast.KindJSDocAugmentsTag { target := typeNodes[0].AsExpressionWithTypeArguments() source := tag.AsJSDocAugmentsTag().ClassName.AsExpressionWithTypeArguments() if !ast.HasSamePropertyAccessName(target.Expression, source.Expression) && target.Expression.Kind == ast.KindIdentifier && source.Expression.Kind == ast.KindIdentifier { return c.grammarErrorOnNode(tag.AsJSDocAugmentsTag().ClassName, diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, tag.AsJSDocAugmentsTag().TagName.Text(), source.Expression.Text(), target.Expression.Text()) } } } } seenExtendsClause = true } else { if heritageClause.Token != ast.KindImplementsKeyword { panic(fmt.Sprintf("Unexpected token %q", heritageClause.Token)) } if seenImplementsClause { return c.grammarErrorOnFirstToken(heritageClauseNode, diagnostics.X_implements_clause_already_seen) } seenImplementsClause = true } // Grammar checking heritageClause inside class declaration c.checkGrammarHeritageClause(heritageClause) } } return false } func (c *Checker) checkGrammarInterfaceDeclaration(node *ast.InterfaceDeclaration) bool { if node.HeritageClauses != nil { seenExtendsClause := false for _, heritageClauseNode := range node.HeritageClauses.Nodes { heritageClause := heritageClauseNode.AsHeritageClause() switch heritageClause.Token { case ast.KindExtendsKeyword: if seenExtendsClause { return c.grammarErrorOnFirstToken(heritageClauseNode, diagnostics.X_extends_clause_already_seen) } seenExtendsClause = true case ast.KindImplementsKeyword: return c.grammarErrorOnFirstToken(heritageClauseNode, diagnostics.Interface_declaration_cannot_have_implements_clause) default: panic(fmt.Sprintf("Unexpected token %q", heritageClause.Token.String())) } // Grammar checking heritageClause inside class declaration c.checkGrammarHeritageClause(heritageClause) } } return false } func (c *Checker) checkGrammarComputedPropertyName(node *ast.Node) bool { // If node is not a computedPropertyName, just skip the grammar checking if node.Kind != ast.KindComputedPropertyName { return false } computedPropertyName := node.AsComputedPropertyName() if computedPropertyName.Expression.Kind == ast.KindBinaryExpression && (computedPropertyName.Expression.AsBinaryExpression()).OperatorToken.Kind == ast.KindCommaToken { return c.grammarErrorOnNode(computedPropertyName.Expression, diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name) } return false } func (c *Checker) checkGrammarForGenerator(node *ast.Node) bool { if bodyData := node.BodyData(); bodyData != nil && bodyData.AsteriskToken != nil { if node.Kind != ast.KindFunctionDeclaration && node.Kind != ast.KindFunctionExpression && node.Kind != ast.KindMethodDeclaration { panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } if node.Flags&ast.NodeFlagsAmbient != 0 { return c.grammarErrorOnNode(bodyData.AsteriskToken, diagnostics.Generators_are_not_allowed_in_an_ambient_context) } if bodyData.Body == nil { return c.grammarErrorOnNode(bodyData.AsteriskToken, diagnostics.An_overload_signature_cannot_be_declared_as_a_generator) } } return false } func (c *Checker) checkGrammarForInvalidQuestionMark(postfixToken *ast.TokenNode, message *diagnostics.Message) bool { return postfixToken != nil && postfixToken.Kind == ast.KindQuestionToken && c.grammarErrorOnNode(postfixToken, message) } func (c *Checker) checkGrammarForInvalidExclamationToken(postfixToken *ast.TokenNode, message *diagnostics.Message) bool { return postfixToken != nil && postfixToken.Kind == ast.KindExclamationToken && c.grammarErrorOnNode(postfixToken, message) } func (c *Checker) checkGrammarObjectLiteralExpression(node *ast.ObjectLiteralExpression, inDestructuring bool) bool { seen := make(map[string]DeclarationMeaning) var properties []*ast.Node if node.Properties != nil { properties = node.Properties.Nodes } for _, prop := range properties { if prop.Kind == ast.KindSpreadAssignment { spreadAssignment := prop.AsSpreadAssignment() if inDestructuring { // a rest property cannot be destructured any further expression := ast.SkipParentheses(spreadAssignment.Expression) if ast.IsArrayLiteralExpression(expression) || ast.IsObjectLiteralExpression(expression) { return c.grammarErrorOnNode(spreadAssignment.Expression, diagnostics.A_rest_element_cannot_contain_a_binding_pattern) } } continue } name := prop.Name() if name.Kind == ast.KindComputedPropertyName { // If the name is not a ComputedPropertyName, the grammar checking will skip it c.checkGrammarComputedPropertyName(name) } if prop.Kind == ast.KindShorthandPropertyAssignment && !inDestructuring { shorthandProp := prop.AsShorthandPropertyAssignment() if shorthandProp.ObjectAssignmentInitializer != nil { // having objectAssignmentInitializer is only valid in an ObjectAssignmentPattern. // Outside of destructuring, it is a syntax error. // Try to grab the last node prior to the initializer, // then error on the first token following (which should be the `=` token). var lastNodeBeforeInitializer *ast.Node shorthandProp.ForEachChild(func(child *ast.Node) bool { if child != shorthandProp.ObjectAssignmentInitializer { lastNodeBeforeInitializer = child return false } return true }) c.grammarErrorOnFirstToken(lastNodeBeforeInitializer, diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern) } } if name.Kind == ast.KindPrivateIdentifier { c.grammarErrorOnNode(name, diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies) } // Modifiers are never allowed on properties except for 'async' on a method declaration if modifiers := prop.Modifiers(); modifiers != nil { if ast.CanHaveModifiers(prop) { for _, mod := range modifiers.Nodes { if ast.IsModifier(mod) && (mod.Kind != ast.KindAsyncKeyword || prop.Kind != ast.KindMethodDeclaration) { c.grammarErrorOnNode(mod, diagnostics.X_0_modifier_cannot_be_used_here, scanner.GetTextOfNode(mod)) } } } else if ast.CanHaveIllegalModifiers(prop) { for _, mod := range modifiers.Nodes { if ast.IsModifier(mod) { c.grammarErrorOnNode(mod, diagnostics.X_0_modifier_cannot_be_used_here, scanner.GetTextOfNode(mod)) } } } } // ECMA-262 11.1.5 Object Initializer // If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true // a.This production is contained in strict code and IsDataDescriptor(previous) is true and // IsDataDescriptor(propId.descriptor) is true. // b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true. // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields var currentKind DeclarationMeaning switch prop.Kind { case ast.KindShorthandPropertyAssignment, ast.KindPropertyAssignment: var commonProp *ast.NamedMemberBase if prop.Kind == ast.KindShorthandPropertyAssignment { prop.ClassLikeData() commonProp = &prop.AsShorthandPropertyAssignment().NamedMemberBase } else { commonProp = &prop.AsPropertyAssignment().NamedMemberBase } // Grammar checking for computedPropertyName and shorthandPropertyAssignment c.checkGrammarForInvalidExclamationToken(commonProp.PostfixToken, diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context) c.checkGrammarForInvalidQuestionMark(commonProp.PostfixToken, diagnostics.An_object_member_cannot_be_declared_optional) if name.Kind == ast.KindNumericLiteral { c.checkGrammarNumericLiteral(name.AsNumericLiteral()) } if name.Kind == ast.KindBigIntLiteral { c.addErrorOrSuggestion(true, createDiagnosticForNode(name, diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name)) } currentKind = DeclarationMeaningPropertyAssignment case ast.KindMethodDeclaration: currentKind = DeclarationMeaningMethod case ast.KindGetAccessor: currentKind = DeclarationMeaningGetAccessor case ast.KindSetAccessor: currentKind = DeclarationMeaningSetAccessor default: panic(fmt.Sprintf("Unexpected node kind %q", prop.Kind)) } if !inDestructuring { effectiveName, ok := c.getEffectivePropertyNameForPropertyNameNode(name) if !ok { continue } existingKind := seen[effectiveName] if existingKind == 0 { seen[effectiveName] = currentKind } else { if (currentKind&DeclarationMeaningMethod != 0) && (existingKind&DeclarationMeaningMethod != 0) { c.grammarErrorOnNode(name, diagnostics.Duplicate_identifier_0, scanner.GetTextOfNode(name)) } else if (currentKind&DeclarationMeaningPropertyAssignment != 0) && (existingKind&DeclarationMeaningPropertyAssignment != 0) { c.grammarErrorOnNode(name, diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, scanner.GetTextOfNode(name)) } else if (currentKind&DeclarationMeaningGetOrSetAccessor != 0) && (existingKind&DeclarationMeaningGetOrSetAccessor != 0) { if existingKind != DeclarationMeaningGetOrSetAccessor && currentKind != existingKind { seen[effectiveName] = currentKind | existingKind } else { return c.grammarErrorOnNode(name, diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name) } } else { return c.grammarErrorOnNode(name, diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name) } } } } return false } func (c *Checker) checkGrammarJsxElement(node *ast.Node) bool { c.checkGrammarJsxName(node.TagName()) c.checkGrammarTypeArguments(node, node.TypeArgumentList()) var seen collections.Set[string] for _, attrNode := range node.Attributes().AsJsxAttributes().Properties.Nodes { if attrNode.Kind == ast.KindJsxSpreadAttribute { continue } attr := attrNode.AsJsxAttribute() name := attr.Name() initializer := attr.Initializer textOfName := name.Text() if !seen.Has(textOfName) { seen.Add(textOfName) } else { return c.grammarErrorOnNode(name, diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name) } if initializer != nil && initializer.Kind == ast.KindJsxExpression && initializer.Expression() == nil { return c.grammarErrorOnNode(initializer, diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression) } } return false } func (c *Checker) checkGrammarJsxName(node *ast.JsxTagNameExpression) bool { if ast.IsPropertyAccessExpression(node) && ast.IsJsxNamespacedName(node.Expression()) { return c.grammarErrorOnNode(node.Expression(), diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names) } if ast.IsJsxNamespacedName(node) && c.compilerOptions.GetJSXTransformEnabled() && !scanner.IsIntrinsicJsxName(node.AsJsxNamespacedName().Namespace.Text()) { return c.grammarErrorOnNode(node, diagnostics.React_components_cannot_include_JSX_namespace_names) } return false } func (c *Checker) checkGrammarJsxExpression(node *ast.JsxExpression) bool { if node.Expression != nil && ast.IsCommaSequence(node.Expression) { return c.grammarErrorOnNode(node.Expression, diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array) } return false } func (c *Checker) checkGrammarForInOrForOfStatement(forInOrOfStatement *ast.ForInOrOfStatement) bool { asNode := forInOrOfStatement.AsNode() if c.checkGrammarStatementInAmbientContext(asNode) { return true } if forInOrOfStatement.Kind == ast.KindForOfStatement && forInOrOfStatement.AwaitModifier != nil { if forInOrOfStatement.Flags&ast.NodeFlagsAwaitContext == 0 { sourceFile := ast.GetSourceFileOfNode(asNode) if ast.IsInTopLevelContext(asNode) { if !c.hasParseDiagnostics(sourceFile) { if !ast.IsEffectiveExternalModule(sourceFile, c.compilerOptions) { c.diagnostics.Add(createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.X_for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module)) } switch c.moduleKind { case core.ModuleKindNode16, core.ModuleKindNode18, core.ModuleKindNode20, core.ModuleKindNodeNext: sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path()) if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { c.diagnostics.Add(createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level)) break } fallthrough case core.ModuleKindES2022, core.ModuleKindESNext, core.ModuleKindPreserve, core.ModuleKindSystem: if c.languageVersion >= core.ScriptTargetES2017 { break } fallthrough default: c.diagnostics.Add(createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher)) } } } else { // use of 'for-await-of' in non-async function if !c.hasParseDiagnostics(sourceFile) { diagnostic := createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.X_for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules) containingFunc := ast.GetContainingFunction(forInOrOfStatement.AsNode()) if containingFunc != nil && containingFunc.Kind != ast.KindConstructor { debug.Assert((getFunctionFlags(containingFunc)&FunctionFlagsAsync) == 0, "Enclosing function should never be an async function.") if hasAsyncModifier(containingFunc) { panic("Enclosing function should never be an async function.") } relatedInfo := createDiagnosticForNode(containingFunc, diagnostics.Did_you_mean_to_mark_this_function_as_async) diagnostic.AddRelatedInfo(relatedInfo) } c.diagnostics.Add(diagnostic) return true } } } } if ast.IsForOfStatement(asNode) && forInOrOfStatement.Flags&ast.NodeFlagsAwaitContext == 0 && ast.IsIdentifier(forInOrOfStatement.Initializer) && forInOrOfStatement.Initializer.Text() == "async" { c.grammarErrorOnNode(forInOrOfStatement.Initializer, diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async) return false } if forInOrOfStatement.Initializer.Kind == ast.KindVariableDeclarationList { variableList := forInOrOfStatement.Initializer.AsVariableDeclarationList() if !c.checkGrammarVariableDeclarationList(variableList) { declarations := variableList.Declarations // declarations.length can be zero if there is an error in variable declaration in for-of or for-in // See http://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements for details // For example: // var let = 10; // for (let of [1,2,3]) {} // this is invalid ES6 syntax // for (let in [1,2,3]) {} // this is invalid ES6 syntax // We will then want to skip on grammar checking on variableList declaration if len(declarations.Nodes) == 0 { return false } if len(declarations.Nodes) > 1 { var diagnostic *diagnostics.Message if forInOrOfStatement.Kind == ast.KindForInStatement { diagnostic = diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement } else { diagnostic = diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement } return c.grammarErrorOnFirstToken(declarations.Nodes[1], diagnostic) } firstVariableDeclaration := declarations.Nodes[0].AsVariableDeclaration() if firstVariableDeclaration.Initializer != nil { var diagnostic *diagnostics.Message if forInOrOfStatement.Kind == ast.KindForInStatement { diagnostic = diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer } else { diagnostic = diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer } return c.grammarErrorOnNode(firstVariableDeclaration.Name(), diagnostic) } if firstVariableDeclaration.Type != nil { var diagnostic *diagnostics.Message if forInOrOfStatement.Kind == ast.KindForInStatement { diagnostic = diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation } else { diagnostic = diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation } return c.grammarErrorOnNode(firstVariableDeclaration.AsNode(), diagnostic) } } } return false } func (c *Checker) checkGrammarAccessor(accessor *ast.AccessorDeclaration) bool { body := accessor.Body() if accessor.Flags&ast.NodeFlagsAmbient == 0 && (accessor.Parent.Kind != ast.KindTypeLiteral) && (accessor.Parent.Kind != ast.KindInterfaceDeclaration) { if c.languageVersion < core.ScriptTargetES2015 && ast.IsPrivateIdentifier(accessor.Name()) { return c.grammarErrorOnNode(accessor.Name(), diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher) } if body == nil && !ast.HasSyntacticModifier(accessor, ast.ModifierFlagsAbstract) { return c.grammarErrorAtPos(accessor, accessor.End()-1, len(";"), diagnostics.X_0_expected, "{") } } if body != nil { if ast.HasSyntacticModifier(accessor, ast.ModifierFlagsAbstract) { return c.grammarErrorOnNode(accessor, diagnostics.An_abstract_accessor_cannot_have_an_implementation) } if accessor.Parent.Kind == ast.KindTypeLiteral || accessor.Parent.Kind == ast.KindInterfaceDeclaration { return c.grammarErrorOnNode(body, diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts) } } funcData := accessor.FunctionLikeData() var typeParameters *ast.NodeList if funcData != nil { typeParameters = funcData.TypeParameters } if typeParameters != nil { return c.grammarErrorOnNode(accessor.Name(), diagnostics.An_accessor_cannot_have_type_parameters) } if !c.doesAccessorHaveCorrectParameterCount(accessor) { return c.grammarErrorOnNode(accessor.Name(), core.IfElse(accessor.Kind == ast.KindGetAccessor, diagnostics.A_get_accessor_cannot_have_parameters, diagnostics.A_set_accessor_must_have_exactly_one_parameter)) } if accessor.Kind == ast.KindSetAccessor { if funcData.Type != nil { return c.grammarErrorOnNode(accessor.Name(), diagnostics.A_set_accessor_cannot_have_a_return_type_annotation) } parameterNode := getSetAccessorValueParameter(accessor) if parameterNode == nil { panic("Return value does not match parameter count assertion.") } parameter := parameterNode.AsParameterDeclaration() if parameter.DotDotDotToken != nil { return c.grammarErrorOnNode(parameter.DotDotDotToken, diagnostics.A_set_accessor_cannot_have_rest_parameter) } if parameter.QuestionToken != nil { return c.grammarErrorOnNode(parameter.QuestionToken, diagnostics.A_set_accessor_cannot_have_an_optional_parameter) } if parameter.Initializer != nil { return c.grammarErrorOnNode(accessor.Name(), diagnostics.A_set_accessor_parameter_cannot_have_an_initializer) } } return false } // Does the accessor have the right number of parameters? // // A `get` accessor has no parameters or a single `this` parameter. // A `set` accessor has one parameter or a `this` parameter and one more parameter. func (c *Checker) doesAccessorHaveCorrectParameterCount(accessor *ast.AccessorDeclaration) bool { // `getAccessorThisParameter` returns `nil` if the accessor's arity is incorrect, // even if there is a `this` parameter declared. return c.getAccessorThisParameter(accessor) != nil || len(accessor.Parameters()) == (core.IfElse(accessor.Kind == ast.KindGetAccessor, 0, 1)) } func (c *Checker) checkGrammarTypeOperatorNode(node *ast.TypeOperatorNode) bool { if node.Operator == ast.KindUniqueKeyword { innerType := node.AsTypeOperatorNode().Type if innerType.Kind != ast.KindSymbolKeyword { return c.grammarErrorOnNode(innerType, diagnostics.X_0_expected, scanner.TokenToString(ast.KindSymbolKeyword)) } parent := ast.WalkUpParenthesizedTypes(node.Parent) switch parent.Kind { case ast.KindVariableDeclaration: decl := parent.AsVariableDeclaration() if decl.Name().Kind != ast.KindIdentifier { return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name) } if !isVariableDeclarationInVariableStatement(decl.AsNode()) { return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement) } if decl.Parent.Flags&ast.NodeFlagsConst == 0 { return c.grammarErrorOnNode((parent.AsVariableDeclaration()).Name(), diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const) } case ast.KindPropertyDeclaration: if !ast.IsStatic(parent) || !hasReadonlyModifier(parent) { return c.grammarErrorOnNode((parent.AsPropertyDeclaration()).Name(), diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly) } case ast.KindPropertySignature: if !ast.HasSyntacticModifier(parent, ast.ModifierFlagsReadonly) { return c.grammarErrorOnNode((parent.AsPropertySignatureDeclaration()).Name(), diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly) } default: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_unique_symbol_types_are_not_allowed_here) } } else if node.Operator == ast.KindReadonlyKeyword { innerType := node.AsTypeOperatorNode().Type if innerType.Kind != ast.KindArrayType && innerType.Kind != ast.KindTupleType { return c.grammarErrorOnFirstToken(node.AsNode(), diagnostics.X_readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, scanner.TokenToString(ast.KindSymbolKeyword)) } } return false } func (c *Checker) checkGrammarForInvalidDynamicName(node *ast.DeclarationName, message *diagnostics.Message) bool { if !c.isNonBindableDynamicName(node) { return false } var expression *ast.Node if ast.IsElementAccessExpression(node) { expression = ast.SkipParentheses(node.AsElementAccessExpression().ArgumentExpression) } else { expression = node.Expression() } if !ast.IsEntityNameExpression(expression) { return c.grammarErrorOnNode(node, message) } return false } // Indicates whether a declaration name is a dynamic name that cannot be late-bound. func (c *Checker) isNonBindableDynamicName(node *ast.DeclarationName) bool { return ast.IsDynamicName(node) && !c.isLateBindableName(node) } func (c *Checker) checkGrammarMethod(node *ast.Node /*Union[MethodDeclaration, MethodSignature]*/) bool { if c.checkGrammarFunctionLikeDeclaration(node) { return true } if node.Kind == ast.KindMethodDeclaration { if node.Parent.Kind == ast.KindObjectLiteralExpression { // We only disallow modifier on a method declaration if it is a property of object-literal-expression if modifiers := node.Modifiers(); modifiers != nil && !(len(modifiers.Nodes) == 1 && modifiers.Nodes[0].Kind == ast.KindAsyncKeyword) { return c.grammarErrorOnFirstToken(node, diagnostics.Modifiers_cannot_appear_here) } methodDecl := node.AsMethodDeclaration() if c.checkGrammarForInvalidQuestionMark(methodDecl.PostfixToken, diagnostics.An_object_member_cannot_be_declared_optional) { return true } if c.checkGrammarForInvalidExclamationToken(methodDecl.PostfixToken, diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context) { return true } if node.Body() == nil { return c.grammarErrorAtPos(node, node.End()-1, len(";"), diagnostics.X_0_expected, "{") } } if c.checkGrammarForGenerator(node) { return true } } if ast.IsClassLike(node.Parent) { if c.languageVersion < core.ScriptTargetES2015 && ast.IsPrivateIdentifier(node.Name()) { return c.grammarErrorOnNode(node.Name(), diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher) } // Technically, computed properties in ambient contexts is disallowed // for property declarations and accessors too, not just methods. // However, property declarations disallow computed names in general, // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. if node.Flags&ast.NodeFlagsAmbient != 0 { return c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) } else if node.Kind == ast.KindMethodDeclaration && node.Body() == nil { return c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) } } else if node.Parent.Kind == ast.KindInterfaceDeclaration { return c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) } else if node.Parent.Kind == ast.KindTypeLiteral { return c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) } return false } func (c *Checker) checkGrammarBreakOrContinueStatement(node *ast.Node) bool { var targetLabel *ast.IdentifierNode switch node.Kind { case ast.KindBreakStatement: targetLabel = node.AsBreakStatement().Label case ast.KindContinueStatement: targetLabel = node.AsContinueStatement().Label default: panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } var current *ast.Node = node for current != nil { if ast.IsFunctionLikeOrClassStaticBlockDeclaration(current) { return c.grammarErrorOnNode(node, diagnostics.Jump_target_cannot_cross_function_boundary) } switch current.Kind { case ast.KindLabeledStatement: if targetLabel != nil && (current.AsLabeledStatement()).Label.Text() == targetLabel.Text() { // found matching label - verify that label usage is correct // continue can only target labels that are on iteration statements isMisplacedContinueLabel := node.Kind == ast.KindContinueStatement && !ast.IsIterationStatement((current.AsLabeledStatement()).Statement, true /*lookInLabeledStatements*/) if isMisplacedContinueLabel { return c.grammarErrorOnNode(node, diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement) } return false } case ast.KindSwitchStatement: if node.Kind == ast.KindBreakStatement && targetLabel == nil { // unlabeled break within switch statement - ok return false } default: if ast.IsIterationStatement(current, false /*lookInLabeledStatements*/) && targetLabel == nil { // unlabeled break or continue within iteration statement - ok return false } } current = current.Parent } if targetLabel != nil { var message *diagnostics.Message if node.Kind == ast.KindBreakStatement { message = diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement } else { message = diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement } return c.grammarErrorOnNode(node, message) } else { var message *diagnostics.Message if node.Kind == ast.KindBreakStatement { message = diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement } else { message = diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement } return c.grammarErrorOnNode(node, message) } } func (c *Checker) checkGrammarBindingElement(node *ast.BindingElement) bool { if node.DotDotDotToken != nil { elements := node.Parent.AsBindingPattern().Elements if node.AsNode() != core.LastOrNil(elements.Nodes) { return c.grammarErrorOnNode(&node.Node, diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern) } c.checkGrammarForDisallowedTrailingComma(elements, diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma) if node.PropertyName != nil { return c.grammarErrorOnNode(node.Name(), diagnostics.A_rest_element_cannot_have_a_property_name) } } if node.DotDotDotToken != nil && node.Initializer != nil { // Error on equals token which immediately precedes the initializer return c.grammarErrorAtPos(node.AsNode(), node.Initializer.Pos()-1, 1, diagnostics.A_rest_element_cannot_have_an_initializer) } return false } func (c *Checker) checkGrammarVariableDeclaration(node *ast.VariableDeclaration) bool { nodeFlags := c.getCombinedNodeFlagsCached(node.AsNode()) blockScopeKind := nodeFlags & ast.NodeFlagsBlockScoped if ast.IsBindingPattern(node.Name()) { switch blockScopeKind { case ast.NodeFlagsAwaitUsing: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_0_declarations_may_not_have_binding_patterns, "await using") case ast.NodeFlagsUsing: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_0_declarations_may_not_have_binding_patterns, "using") } } if node.Parent.Parent.Kind != ast.KindForInStatement && node.Parent.Parent.Kind != ast.KindForOfStatement { if nodeFlags&ast.NodeFlagsAmbient != 0 { c.checkAmbientInitializer(node.AsNode()) } else if node.Initializer == nil { if ast.IsBindingPattern(node.Name()) && !ast.IsBindingPattern(node.Parent) { return c.grammarErrorOnNode(node.AsNode(), diagnostics.A_destructuring_declaration_must_have_an_initializer) } switch blockScopeKind { case ast.NodeFlagsAwaitUsing: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_0_declarations_must_be_initialized, "await using") case ast.NodeFlagsUsing: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_0_declarations_must_be_initialized, "using") case ast.NodeFlagsConst: return c.grammarErrorOnNode(node.AsNode(), diagnostics.X_0_declarations_must_be_initialized, "const") } } } if node.ExclamationToken != nil && (node.Parent.Parent.Kind != ast.KindVariableStatement || node.Type == nil || node.Initializer != nil || nodeFlags&ast.NodeFlagsAmbient != 0) { var message *diagnostics.Message switch { case node.Initializer != nil: message = diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions case node.Type == nil: message = diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations default: message = diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context } return c.grammarErrorOnNode(node.ExclamationToken, message) } if c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node.AsNode())) < core.ModuleKindSystem && (node.Parent.Parent.Flags&ast.NodeFlagsAmbient == 0) && ast.HasSyntacticModifier(node.Parent.Parent, ast.ModifierFlagsExport) { c.checkGrammarForEsModuleMarkerInBindingName(node.Name()) } // 1. LexicalDeclaration : LetOrConst BindingList ; // It is a Syntax Error if the BoundNames of BindingList contains "let". // 2. ForDeclaration: ForDeclaration : LetOrConst ForBinding // It is a Syntax Error if the BoundNames of ForDeclaration contains "let". // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code // and its Identifier is eval or arguments return blockScopeKind != 0 && c.checkGrammarNameInLetOrConstDeclarations(node.Name()) } func (c *Checker) checkGrammarForEsModuleMarkerInBindingName(name *ast.Node) bool { if ast.IsIdentifier(name) { if name.Text() == "__esModule" { return c.grammarErrorOnNodeSkippedOnNoEmit(name, diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules) } } else { for _, element := range name.AsBindingPattern().Elements.Nodes { if element.Name() != nil { return c.checkGrammarForEsModuleMarkerInBindingName(element.Name()) } } } return false } func (c *Checker) checkGrammarNameInLetOrConstDeclarations(name *ast.Node /*Union[Identifier, BindingPattern]*/) bool { if name.Kind == ast.KindIdentifier { if name.AsIdentifier().Text == "let" { return c.grammarErrorOnNode(name, diagnostics.X_let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations) } } else { elements := name.AsBindingPattern().Elements.Nodes for _, element := range elements { bindingElement := element.AsBindingElement() if bindingElement.Name() != nil { c.checkGrammarNameInLetOrConstDeclarations(bindingElement.Name()) } } } return false } func (c *Checker) checkGrammarVariableDeclarationList(declarationList *ast.VariableDeclarationList) bool { declarations := declarationList.Declarations if c.checkGrammarForDisallowedTrailingComma(declarations, diagnostics.Trailing_comma_not_allowed) { return true } if len(declarations.Nodes) == 0 { return c.grammarErrorAtPos(declarationList.AsNode(), declarations.Pos(), declarations.End()-declarations.Pos(), diagnostics.Variable_declaration_list_cannot_be_empty) } blockScopeFlags := declarationList.Flags & ast.NodeFlagsBlockScoped if blockScopeFlags == ast.NodeFlagsUsing || blockScopeFlags == ast.NodeFlagsAwaitUsing { if ast.IsForInStatement(declarationList.Parent) { return c.grammarErrorOnNode(declarationList.AsNode(), core.IfElse(blockScopeFlags == ast.NodeFlagsUsing, diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_using_declaration, diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_an_await_using_declaration)) } if declarationList.Flags&ast.NodeFlagsAmbient != 0 { return c.grammarErrorOnNode(declarationList.AsNode(), core.IfElse(blockScopeFlags == ast.NodeFlagsUsing, diagnostics.X_using_declarations_are_not_allowed_in_ambient_contexts, diagnostics.X_await_using_declarations_are_not_allowed_in_ambient_contexts)) } } if blockScopeFlags == ast.NodeFlagsAwaitUsing { return c.checkGrammarAwaitOrAwaitUsing(declarationList.AsNode()) } return false } func (c *Checker) checkGrammarAwaitOrAwaitUsing(node *ast.Node) bool { // Grammar checking hasError := false container := getContainingFunctionOrClassStaticBlock(node) if container != nil && ast.IsClassStaticBlockDeclaration(container) { // NOTE: We report this regardless as to whether there are parse diagnostics. var message *diagnostics.Message if ast.IsAwaitExpression(node) { message = diagnostics.X_await_expression_cannot_be_used_inside_a_class_static_block } else { message = diagnostics.X_await_using_statements_cannot_be_used_inside_a_class_static_block } c.error(node, message) hasError = true } else if node.Flags&ast.NodeFlagsAwaitContext == 0 { if ast.IsInTopLevelContext(node) { sourceFile := ast.GetSourceFileOfNode(node) if !c.hasParseDiagnostics(sourceFile) { var span core.TextRange var spanCalculated bool if !ast.IsEffectiveExternalModule(sourceFile, c.compilerOptions) { span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) spanCalculated = true var message *diagnostics.Message if ast.IsAwaitExpression(node) { message = diagnostics.X_await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module } else { message = diagnostics.X_await_using_statements_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module } diagnostic := ast.NewDiagnostic(sourceFile, span, message) c.diagnostics.Add(diagnostic) hasError = true } switch c.moduleKind { case core.ModuleKindNode16, core.ModuleKindNode18, core.ModuleKindNode20, core.ModuleKindNodeNext: sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path()) if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { if !spanCalculated { span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) } c.diagnostics.Add(ast.NewDiagnostic(sourceFile, span, diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level)) hasError = true break } fallthrough case core.ModuleKindES2022, core.ModuleKindESNext, core.ModuleKindPreserve, core.ModuleKindSystem: if c.languageVersion >= core.ScriptTargetES2017 { break } fallthrough default: if !spanCalculated { span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) } var message *diagnostics.Message if ast.IsAwaitExpression(node) { message = diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher } else { message = diagnostics.Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher } c.diagnostics.Add(ast.NewDiagnostic(sourceFile, span, message)) hasError = true } } } else { // use of 'await' in non-async function sourceFile := ast.GetSourceFileOfNode(node) if !c.hasParseDiagnostics(sourceFile) { span := scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) var message *diagnostics.Message if ast.IsAwaitExpression(node) { message = diagnostics.X_await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules } else { message = diagnostics.X_await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules } diagnostic := ast.NewDiagnostic(sourceFile, span, message) if container != nil && container.Kind != ast.KindConstructor && !hasAsyncModifier(container) { relatedInfo := NewDiagnosticForNode(container, diagnostics.Did_you_mean_to_mark_this_function_as_async) diagnostic.AddRelatedInfo(relatedInfo) } c.diagnostics.Add(diagnostic) hasError = true } } } if ast.IsAwaitExpression(node) && c.isInParameterInitializerBeforeContainingFunction(node) { // NOTE: We report this regardless as to whether there are parse diagnostics. c.error(node, diagnostics.X_await_expressions_cannot_be_used_in_a_parameter_initializer) hasError = true } return hasError } func (c *Checker) checkGrammarYieldExpression(node *ast.Node) bool { hasError := false if node.Flags&ast.NodeFlagsYieldContext == 0 { c.grammarErrorOnFirstToken(node, diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body) hasError = true } if c.isInParameterInitializerBeforeContainingFunction(node) { c.error(node, diagnostics.X_yield_expressions_cannot_be_used_in_a_parameter_initializer) hasError = true } return hasError } func (c *Checker) checkGrammarForDisallowedBlockScopedVariableStatement(node *ast.VariableStatement) bool { if !c.containerAllowsBlockScopedVariable(node.Parent) { blockScopeKind := c.getCombinedNodeFlagsCached(node.DeclarationList) & ast.NodeFlagsBlockScoped if blockScopeKind != 0 { var keyword string switch { case blockScopeKind == ast.NodeFlagsLet: keyword = "let" case blockScopeKind == ast.NodeFlagsConst: keyword = "const" case blockScopeKind == ast.NodeFlagsUsing: keyword = "using" case blockScopeKind == ast.NodeFlagsAwaitUsing: keyword = "await using" default: panic("Unknown BlockScope flag") } c.error(node.AsNode(), diagnostics.X_0_declarations_can_only_be_declared_inside_a_block, keyword) } } return false } func (c *Checker) containerAllowsBlockScopedVariable(parent *ast.Node) bool { switch parent.Kind { case ast.KindIfStatement, ast.KindDoStatement, ast.KindWhileStatement, ast.KindWithStatement, ast.KindForStatement, ast.KindForInStatement, ast.KindForOfStatement: return false case ast.KindLabeledStatement: return c.containerAllowsBlockScopedVariable(parent.Parent) } return true } func (c *Checker) checkGrammarMetaProperty(node *ast.MetaProperty) bool { nodeName := node.Name() nameText := nodeName.Text() switch node.KeywordToken { case ast.KindNewKeyword: if nameText != "target" { return c.grammarErrorOnNode(nodeName, diagnostics.X_0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, nameText, scanner.TokenToString(node.KeywordToken), "target") } case ast.KindImportKeyword: if nameText != "meta" { isCallee := ast.IsCallExpression(node.Parent) && node.Parent.AsCallExpression().Expression == node.AsNode() if nameText == "defer" { if !isCallee { return c.grammarErrorAtPos(node.AsNode(), node.AsNode().End(), 0, diagnostics.X_0_expected, "(") } } else { if isCallee { return c.grammarErrorOnNode(nodeName, diagnostics.X_0_is_not_a_valid_meta_property_for_keyword_import_Did_you_mean_meta_or_defer, nameText) } return c.grammarErrorOnNode(nodeName, diagnostics.X_0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, nameText, scanner.TokenToString(node.KeywordToken), "meta") } } } return false } func (c *Checker) checkGrammarConstructorTypeParameters(node *ast.ConstructorDeclaration) bool { range_ := node.TypeParameters if range_ != nil { var pos int if range_.Pos() == range_.End() { pos = range_.Pos() } else { pos = scanner.SkipTrivia(ast.GetSourceFileOfNode(node.AsNode()).Text(), range_.Pos()) } return c.grammarErrorAtPos(node.AsNode(), pos, range_.End()-pos, diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration) } return false } func (c *Checker) checkGrammarConstructorTypeAnnotation(node *ast.ConstructorDeclaration) bool { t := node.Type if t != nil { return c.grammarErrorOnNode(t, diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration) } return false } func (c *Checker) checkGrammarProperty(node *ast.Node /*Union[PropertyDeclaration, PropertySignature]*/) bool { propertyName := node.Name() if ast.IsComputedPropertyName(propertyName) && ast.IsBinaryExpression(propertyName.Expression()) && propertyName.Expression().AsBinaryExpression().OperatorToken.Kind == ast.KindInKeyword { return c.grammarErrorOnNode(node.Parent.Members()[0], diagnostics.A_mapped_type_may_not_declare_properties_or_methods) } if ast.IsClassLike(node.Parent) { if ast.IsStringLiteral(propertyName) && propertyName.Text() == "constructor" { return c.grammarErrorOnNode(propertyName, diagnostics.Classes_may_not_have_a_field_named_constructor) } if c.checkGrammarForInvalidDynamicName(propertyName, diagnostics.A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type) { return true } if c.languageVersion < core.ScriptTargetES2015 && ast.IsPrivateIdentifier(propertyName) { return c.grammarErrorOnNode(propertyName, diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher) } if c.languageVersion < core.ScriptTargetES2015 && ast.IsAutoAccessorPropertyDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 { return c.grammarErrorOnNode(propertyName, diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher) } if ast.IsAutoAccessorPropertyDeclaration(node) && c.checkGrammarForInvalidQuestionMark(node.AsPropertyDeclaration().PostfixToken, diagnostics.An_accessor_property_cannot_be_declared_optional) { return true } } else if ast.IsInterfaceDeclaration(node.Parent) { if c.checkGrammarForInvalidDynamicName(propertyName, diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) { return true } if !ast.IsPropertySignatureDeclaration(node) { // Interfaces cannot contain property declarations panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } if initializer := node.AsPropertySignatureDeclaration().Initializer; initializer != nil { return c.grammarErrorOnNode(initializer, diagnostics.An_interface_property_cannot_have_an_initializer) } } else if ast.IsTypeLiteralNode(node.Parent) { if c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) { return true } if !ast.IsPropertySignatureDeclaration(node) { // Type literals cannot contain property declarations panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } if initializer := node.AsPropertySignatureDeclaration().Initializer; initializer != nil { return c.grammarErrorOnNode(initializer, diagnostics.A_type_literal_property_cannot_have_an_initializer) } } if node.Flags&ast.NodeFlagsAmbient != 0 { c.checkAmbientInitializer(node) } if ast.IsPropertyDeclaration(node) { propDecl := node.AsPropertyDeclaration() postfixToken := propDecl.PostfixToken if postfixToken != nil && postfixToken.Kind == ast.KindExclamationToken { switch { case propDecl.Initializer != nil: return c.grammarErrorOnNode(postfixToken, diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions) case propDecl.Type == nil: return c.grammarErrorOnNode(postfixToken, diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations) case !ast.IsClassLike(node.Parent) || node.Flags&ast.NodeFlagsAmbient != 0 || ast.IsStatic(node) || hasAbstractModifier(node): return c.grammarErrorOnNode(postfixToken, diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context) } } } return false } func (c *Checker) checkAmbientInitializer(node *ast.Node) bool { var initializer *ast.Expression var typeNode *ast.TypeNode switch node.Kind { case ast.KindVariableDeclaration: varDecl := node.AsVariableDeclaration() initializer = varDecl.Initializer typeNode = varDecl.Type case ast.KindPropertyDeclaration: propDecl := node.AsPropertyDeclaration() initializer = propDecl.Initializer typeNode = propDecl.Type case ast.KindPropertySignature: propSig := node.AsPropertySignatureDeclaration() initializer = propSig.Initializer typeNode = propSig.Type default: panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } if initializer != nil { isInvalidInitializer := !(isInitializerStringOrNumberLiteralExpression(initializer) || c.isInitializerSimpleLiteralEnumReference(initializer) || initializer.Kind == ast.KindTrueKeyword || initializer.Kind == ast.KindFalseKeyword || isInitializerBigIntLiteralExpression(initializer)) isConstOrReadonly := isDeclarationReadonly(node) || ast.IsVariableDeclaration(node) && (c.isVarConstLike(node)) if isConstOrReadonly && (typeNode == nil) { if isInvalidInitializer { return c.grammarErrorOnNode(initializer, diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference) } } else { return c.grammarErrorOnNode(initializer, diagnostics.Initializers_are_not_allowed_in_ambient_contexts) } } return false } func isInitializerStringOrNumberLiteralExpression(expr *ast.Expression) bool { return ast.IsStringOrNumericLiteralLike(expr) || expr.Kind == ast.KindPrefixUnaryExpression && (expr.AsPrefixUnaryExpression()).Operator == ast.KindMinusToken && (expr.AsPrefixUnaryExpression()).Operand.Kind == ast.KindNumericLiteral } func isInitializerBigIntLiteralExpression(expr *ast.Expression) bool { if expr.Kind == ast.KindBigIntLiteral { return true } if expr.Kind == ast.KindPrefixUnaryExpression { unaryExpr := expr.AsPrefixUnaryExpression() return unaryExpr.Operator == ast.KindMinusToken && unaryExpr.Operand.Kind == ast.KindBigIntLiteral } return false } func (c *Checker) isInitializerSimpleLiteralEnumReference(expr *ast.Expression) bool { if ast.IsPropertyAccessExpression(expr) { return c.checkExpressionCached(expr).flags&TypeFlagsEnumLike != 0 } if ast.IsElementAccessExpression(expr) { elementAccess := expr.AsElementAccessExpression() return isInitializerStringOrNumberLiteralExpression(elementAccess.ArgumentExpression) && ast.IsEntityNameExpression(elementAccess.Expression) && c.checkExpressionCached(expr).flags&TypeFlagsEnumLike != 0 } return false } func (c *Checker) checkGrammarTopLevelElementForRequiredDeclareModifier(node *ast.Node) bool { // A declare modifier is required for any top level .d.ts declaration except export=, export default, export as namespace // interfaces and imports categories: // // DeclarationElement: // ExportAssignment // export_opt InterfaceDeclaration // export_opt TypeAliasDeclaration // export_opt ImportDeclaration // export_opt ExternalImportDeclaration // export_opt AmbientDeclaration // // TODO: The spec needs to be amended to reflect this grammar. if node.Kind == ast.KindInterfaceDeclaration || node.Kind == ast.KindTypeAliasDeclaration || node.Kind == ast.KindImportDeclaration || node.Kind == ast.KindJSImportDeclaration || node.Kind == ast.KindImportEqualsDeclaration || node.Kind == ast.KindExportDeclaration || node.Kind == ast.KindExportAssignment || node.Kind == ast.KindJSExportAssignment || node.Kind == ast.KindNamespaceExportDeclaration || ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient|ast.ModifierFlagsExport|ast.ModifierFlagsDefault) { return false } return c.grammarErrorOnFirstToken(node, diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier) } func (c *Checker) checkGrammarTopLevelElementsForRequiredDeclareModifier(file *ast.SourceFile) bool { for _, decl := range file.Statements.Nodes { if ast.IsDeclarationNode(decl) || decl.Kind == ast.KindVariableStatement { if c.checkGrammarTopLevelElementForRequiredDeclareModifier(decl) { return true } } } return false } func (c *Checker) checkGrammarSourceFile(node *ast.SourceFile) bool { return node.Flags&ast.NodeFlagsAmbient != 0 && c.checkGrammarTopLevelElementsForRequiredDeclareModifier(node) } func (c *Checker) checkGrammarStatementInAmbientContext(node *ast.Node) bool { if node.Flags&ast.NodeFlagsAmbient != 0 { // Find containing block which is either Block, ModuleBlock, SourceFile links := c.nodeLinks.Get(node) if !links.hasReportedStatementInAmbientContext && (ast.IsFunctionLike(node.Parent) || ast.IsAccessor(node.Parent)) { links.hasReportedStatementInAmbientContext = c.grammarErrorOnFirstToken(node, diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts) return links.hasReportedStatementInAmbientContext } // We are either parented by another statement, or some sort of block. // If we're in a block, we only want to really report an error once // to prevent noisiness. So use a bit on the block to indicate if // this has already been reported, and don't report if it has. // if node.Parent.Kind == ast.KindBlock || node.Parent.Kind == ast.KindModuleBlock || node.Parent.Kind == ast.KindSourceFile { links := c.nodeLinks.Get(node.Parent) // Check if the containing block ever report this error if !links.hasReportedStatementInAmbientContext { links.hasReportedStatementInAmbientContext = c.grammarErrorOnFirstToken(node, diagnostics.Statements_are_not_allowed_in_ambient_contexts) return links.hasReportedStatementInAmbientContext } } else { // We must be parented by a statement. If so, there's no need // to report the error as our parent will have already done it. // debug.Assert(ast.IsStatement(node.Parent)) // !!! commented out in strada - fails if uncommented } } return false } func (c *Checker) checkGrammarNumericLiteral(node *ast.NumericLiteral) { nodeText := scanner.GetTextOfNode(node.AsNode()) // Realism (size) checking // We should test against `getTextOfNode(node)` rather than `node.text`, because `node.text` for large numeric literals can contain "." // e.g. `node.text` for numeric literal `1100000000000000000000` is `1.1e21`. isFractional := strings.ContainsRune(nodeText, '.') // !!! // isScientific := node.NumericLiteralFlags & ast.TokenFlagsScientific isScientific := strings.ContainsRune(nodeText, 'e') // Scientific notation (e.g. 2e54 and 1e00000000010) can't be converted to bigint // Fractional numbers (e.g. 9000000000000000.001) are inherently imprecise anyway if isFractional || isScientific { return } // Here `node` is guaranteed to be a numeric literal representing an integer. // We need to judge whether the integer `node` represents is <= 2 ** 53 - 1, which can be accomplished by comparing to `value` defined below because: // 1) when `node` represents an integer <= 2 ** 53 - 1, `node.text` is its exact string representation and thus `value` precisely represents the integer. // 2) otherwise, although `node.text` may be imprecise string representation, its mathematical value and consequently `value` cannot be less than 2 ** 53, // thus the result of the predicate won't be affected. value := jsnum.FromString(node.Text) if value <= jsnum.MaxSafeInteger { return } c.addErrorOrSuggestion(false, createDiagnosticForNode(node.AsNode(), diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers)) } func (c *Checker) checkGrammarBigIntLiteral(node *ast.BigIntLiteral) bool { literalType := ast.IsLiteralTypeNode(node.Parent) || ast.IsPrefixUnaryExpression(node.Parent) && ast.IsLiteralTypeNode(node.Parent.Parent) if !literalType { // Don't error on BigInt literals in ambient contexts if node.Flags&ast.NodeFlagsAmbient == 0 && c.languageVersion < core.ScriptTargetES2020 { if c.grammarErrorOnNode(node.AsNode(), diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020) { return true } } } return false } func (c *Checker) checkGrammarImportClause(node *ast.ImportClause) bool { switch node.PhaseModifier { case ast.KindTypeKeyword: if node.Flags&ast.NodeFlagsJSDoc == 0 && node.Name() != nil && node.NamedBindings != nil { return c.grammarErrorOnNode(&node.Node, diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both) } if node.NamedBindings != nil && node.NamedBindings.Kind == ast.KindNamedImports { return c.checkGrammarTypeOnlyNamedImportsOrExports(node.NamedBindings) } case ast.KindDeferKeyword: if node.Name() != nil { return c.grammarErrorOnNode(&node.Node, diagnostics.Default_imports_are_not_allowed_in_a_deferred_import) } if node.NamedBindings != nil && node.NamedBindings.Kind == ast.KindNamedImports { return c.grammarErrorOnNode(&node.Node, diagnostics.Named_imports_are_not_allowed_in_a_deferred_import) } if c.moduleKind != core.ModuleKindESNext && c.moduleKind != core.ModuleKindPreserve { return c.grammarErrorOnNode(&node.Node, diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve) } } return false } func (c *Checker) checkGrammarTypeOnlyNamedImportsOrExports(namedBindings *ast.Node) bool { var nodeList *ast.NodeList if namedBindings.Kind == ast.KindNamedImports { nodeList = namedBindings.AsNamedImports().Elements } else { nodeList = namedBindings.AsNamedExports().Elements } for _, specifier := range nodeList.Nodes { var specifierIsTypeOnly bool var message *diagnostics.Message if specifier.Kind == ast.KindImportSpecifier { specifierIsTypeOnly = specifier.AsImportSpecifier().IsTypeOnly message = diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement } else { specifierIsTypeOnly = specifier.AsExportSpecifier().IsTypeOnly message = diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement } if specifierIsTypeOnly { return c.grammarErrorOnFirstToken(specifier, message) } } return false } func (c *Checker) checkGrammarImportCallExpression(node *ast.Node) bool { if c.compilerOptions.VerbatimModuleSyntax == core.TSTrue && c.moduleKind == core.ModuleKindCommonJS { return c.grammarErrorOnNode(node, getVerbatimModuleSyntaxErrorMessage(node)) } if node.Expression().Kind == ast.KindMetaProperty { if c.moduleKind != core.ModuleKindESNext && c.moduleKind != core.ModuleKindPreserve { return c.grammarErrorOnNode(node, diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve) } } else if c.moduleKind == core.ModuleKindES2015 { return c.grammarErrorOnNode(node, diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_node18_node20_or_nodenext) } nodeAsCall := node.AsCallExpression() if nodeAsCall.TypeArguments != nil { return c.grammarErrorOnNode(node, diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments) } nodeArguments := nodeAsCall.Arguments argumentNodes := nodeArguments.Nodes if c.moduleKind != core.ModuleKindESNext && c.moduleKind != core.ModuleKindNodeNext && c.moduleKind != core.ModuleKindNode16 && c.moduleKind != core.ModuleKindPreserve { // We are allowed trailing comma after proposal-import-assertions. c.checkGrammarForDisallowedTrailingComma(nodeArguments, diagnostics.Trailing_comma_not_allowed) if len(argumentNodes) > 1 { importAttributesArgument := argumentNodes[1] return c.grammarErrorOnNode(importAttributesArgument, diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_node18_node20_nodenext_or_preserve) } } if len(argumentNodes) == 0 || len(argumentNodes) > 2 { return c.grammarErrorOnNode(node, diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_set_of_attributes_as_arguments) } // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. // parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import. spreadElement := core.Find(argumentNodes, ast.IsSpreadElement) if spreadElement != nil { return c.grammarErrorOnNode(spreadElement, diagnostics.Argument_of_dynamic_import_cannot_be_spread_element) } return false }