Skip to content

Fix multiple issues uncovered by test suites #641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
99c2b90
Fix printing of empty enum types
ahejlsberg Mar 15, 2025
f50647c
Properly format dotted names in diagnostic merging
ahejlsberg Mar 15, 2025
ab7f1a3
Accept new baselines
ahejlsberg Mar 15, 2025
bace2c3
Don't elaborate on type parameter mismatch errors
ahejlsberg Mar 15, 2025
2257787
Accept new baselines
ahejlsberg Mar 15, 2025
37ed8d5
Implicit export modifier for nested namespaces
ahejlsberg Mar 15, 2025
7bb923b
Accept new baselines
ahejlsberg Mar 15, 2025
0b454ca
Print fully qualified type names when requested
ahejlsberg Mar 15, 2025
0af89df
Accept new baselines
ahejlsberg Mar 15, 2025
3af9692
Fix constructor accessibility check
ahejlsberg Mar 16, 2025
7d62932
Accept new baselines
ahejlsberg Mar 16, 2025
b88efa3
Properly initialize Binder.inStrictMode
ahejlsberg Mar 16, 2025
8ce047d
Accept new baselines
ahejlsberg Mar 16, 2025
3025be2
Fix typo in checkPropertyAccessExpressionOrQualifiedName
ahejlsberg Mar 16, 2025
2508f30
Accept new baselines
ahejlsberg Mar 16, 2025
61b57a9
Remove errant quotes
ahejlsberg Mar 16, 2025
f683251
Accept new baselines
ahejlsberg Mar 16, 2025
fd94aad
Print qualified name with typeof when requested
ahejlsberg Mar 16, 2025
5c81e82
Accept new baselines
ahejlsberg Mar 16, 2025
bcbbf56
Port misspelled keyword suggestion logic
ahejlsberg Mar 16, 2025
789c09a
Accept new baselines
ahejlsberg Mar 16, 2025
85def79
Fix property grammar check
ahejlsberg Mar 16, 2025
86baaa6
Accept new baselines
ahejlsberg Mar 16, 2025
81d15cc
Fix fresh type of computed enum types
ahejlsberg Mar 16, 2025
18e8063
Accept new baselines
ahejlsberg Mar 16, 2025
e46218c
Check enum members + fix overshift warning
ahejlsberg Mar 16, 2025
f3af365
Accept new baselines
ahejlsberg Mar 16, 2025
dbcf8cd
Simple free list for Relater objects
ahejlsberg Mar 17, 2025
f6c028a
Accept new baselines
ahejlsberg Mar 17, 2025
e8f7945
Merge branch 'main' into more-types-37
ahejlsberg Mar 17, 2025
ff5ab09
Accept new baselines
ahejlsberg Mar 17, 2025
aecd11d
Use Number.Remainder and fix issue in that function
ahejlsberg Mar 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ func (n *Node) ModifierFlags() ModifierFlags {
if modifiers != nil {
return modifiers.ModifierFlags
}
if n.Flags&NodeFlagsNestedNamespace != 0 {
return ModifierFlagsExport
}
return ModifierFlagsNone
}

Expand Down
2 changes: 1 addition & 1 deletion internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func bindSourceFile(file *ast.SourceFile, options *core.CompilerOptions) {
b.file = file
b.options = options
b.languageVersion = options.GetEmitScriptTarget()
b.inStrictMode = options.AlwaysStrict.IsTrue()
b.inStrictMode = (options.AlwaysStrict.IsTrue() || options.Strict.IsTrue()) && !file.IsDeclarationFile || ast.IsExternalModule(file)
b.unreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
b.reportedUnreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
b.bind(file.AsNode())
Expand Down
24 changes: 19 additions & 5 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ type Checker struct {
reverseMappedSourceStack []*Type
reverseMappedTargetStack []*Type
reverseExpandingFlags ExpandingFlags
relaters []Relater
freeRelater *Relater
subtypeRelation *Relation
strictSubtypeRelation *Relation
assignableRelation *Relation
Expand Down Expand Up @@ -791,6 +791,7 @@ type Checker struct {
getGlobalClassMethodDecoratorContextType func() *Type
getGlobalClassGetterDecoratorContextType func() *Type
getGlobalClassSetterDecoratorContextType func() *Type
getGlobalClassAccessorDecoratorContxtType func() *Type
getGlobalClassAccessorDecoratorContextType func() *Type
getGlobalClassAccessorDecoratorTargetType func() *Type
getGlobalClassAccessorDecoratorResultType func() *Type
Expand Down Expand Up @@ -2171,6 +2172,8 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) {
c.checkTypeAliasDeclaration(node)
case ast.KindEnumDeclaration:
c.checkEnumDeclaration(node)
case ast.KindEnumMember:
c.checkEnumMember(node)
case ast.KindModuleDeclaration:
c.checkModuleDeclaration(node)
case ast.KindImportDeclaration:
Expand Down Expand Up @@ -4270,7 +4273,7 @@ basePropertyCheck:
for errorNode, memberInfo := range notImplementedInfo {
switch {
case len(memberInfo.missedProperties) == 1:
missedProperty := "'" + memberInfo.missedProperties[0] + "'"
missedProperty := memberInfo.missedProperties[0]
if ast.IsClassExpression(errorNode) {
c.error(errorNode, diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, missedProperty, memberInfo.baseTypeName)
} else {
Expand Down Expand Up @@ -4711,6 +4714,15 @@ func (c *Checker) checkEnumDeclaration(node *ast.Node) {
}
}

func (c *Checker) checkEnumMember(node *ast.Node) {
if ast.IsPrivateIdentifier(node.Name()) {
c.error(node, diagnostics.An_enum_member_cannot_be_named_with_a_private_identifier)
}
if node.Initializer() != nil {
c.checkExpression(node.Initializer())
}
}

func (c *Checker) checkModuleDeclaration(node *ast.Node) {
if body := node.Body(); body != nil {
c.checkSourceElement(body)
Expand Down Expand Up @@ -8025,7 +8037,7 @@ func (c *Checker) isConstructorAccessible(node *ast.Node, signature *Signature)
declaration := signature.declaration
modifiers := getSelectedEffectiveModifierFlags(declaration, ast.ModifierFlagsNonPublicAccessibilityModifier)
// (1) Public constructors and (2) constructor functions are always accessible.
if modifiers == 0 || ast.IsConstructorDeclaration(declaration) {
if modifiers == 0 || !ast.IsConstructorDeclaration(declaration) {
return true
}
declaringClassDeclaration := getClassLikeDeclarationOfSymbol(declaration.Parent.Symbol())
Expand Down Expand Up @@ -10449,7 +10461,7 @@ func (c *Checker) checkPropertyAccessChain(node *ast.Node, checkMode CheckMode)
}

func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, left *ast.Node, leftType *Type, right *ast.Node, checkMode CheckMode, writeOnly bool) *Type {
parentSymbol := c.typeNodeLinks.Get(node).resolvedSymbol
parentSymbol := c.typeNodeLinks.Get(left).resolvedSymbol
assignmentKind := getAssignmentTargetKind(node)
widenedType := leftType
if assignmentKind != AssignmentKindNone || c.isMethodAccessForCall(node) {
Expand Down Expand Up @@ -11521,7 +11533,8 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N
ast.KindGreaterThanGreaterThanGreaterThanEqualsToken:
rhsEval := c.evaluate(right, right)
if numValue, ok := rhsEval.Value.(jsnum.Number); ok && numValue.Abs() >= 32 {
c.errorOrSuggestion(ast.IsEnumMember(ast.WalkUpParenthesizedExpressions(right.Parent.Parent)), errorNode, diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2, scanner.GetTextOfNode(left), scanner.TokenToString(operator), (numValue / 32).Floor())
// Elevate from suggestion to error within an enum member
c.errorOrSuggestion(ast.IsEnumMember(ast.WalkUpParenthesizedExpressions(right.Parent.Parent)), errorNode, diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2, scanner.GetTextOfNode(left), scanner.TokenToString(operator), numValue.Remainder(32))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably just numValue.Remainder(32)? I'd rather not rely on the math package outside of jsnum; I eliminated it everywhere except for the max int consts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll switch to Number.Remainder. Which by the way has a bug in it that I'll also fix.

}
}
}
Expand Down Expand Up @@ -21885,6 +21898,7 @@ func (c *Checker) createComputedEnumType(symbol *ast.Symbol) *Type {
freshType := c.newLiteralType(TypeFlagsEnum, nil, regularType)
freshType.symbol = symbol
regularType.AsLiteralType().freshType = freshType
freshType.AsLiteralType().freshType = freshType
return regularType
}

Expand Down
8 changes: 3 additions & 5 deletions internal/checker/grammarchecks.go
Original file line number Diff line number Diff line change
Expand Up @@ -1907,24 +1907,22 @@ func (c *Checker) checkGrammarProperty(node *ast.Node /*Union[PropertyDeclaratio
if ast.IsAutoAccessorPropertyDeclaration(node) && c.checkGrammarForInvalidQuestionMark(node.AsPropertyDeclaration().PostfixToken, diagnostics.An_accessor_property_cannot_be_declared_optional) {
return true
}
} else if node.Parent.Kind == ast.KindInterfaceDeclaration {
} 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.IsTypeAliasDeclaration(node.Parent) {
} 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) {
if !ast.IsPropertySignatureDeclaration(node) {
// Type literals cannot contain property declarations
panic(fmt.Sprintf("Unexpected node kind %q", node.Kind))
}
Expand Down
40 changes: 26 additions & 14 deletions internal/checker/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ func (p *Printer) printName(symbol *ast.Symbol) {
p.print(p.c.symbolToString(symbol))
}

func (p *Printer) printQualifiedName(symbol *ast.Symbol) {
if p.flags&TypeFormatFlagsUseFullyQualifiedType != 0 && symbol.Parent != nil {
p.printQualifiedName(symbol.Parent)
p.print(".")
}
if symbol.Flags&ast.SymbolFlagsModule != 0 && strings.HasPrefix(symbol.Name, "\"") {
p.print("import(")
p.print(symbol.Name)
p.print(")")
return
}
p.printName(symbol)
}

func (p *Printer) printTypeEx(t *Type, precedence ast.TypePrecedence) {
if p.c.getTypePrecedence(t) < precedence {
p.print("(")
Expand All @@ -139,7 +153,7 @@ func (p *Printer) printType(t *Type) {
}

if t.alias != nil && (p.flags&TypeFormatFlagsInTypeAlias == 0 || p.depth > 0) {
p.printName(t.alias.symbol)
p.printQualifiedName(t.alias.symbol)
p.printTypeArguments(t.alias.typeArguments)
} else {
p.printTypeNoAlias(t)
Expand Down Expand Up @@ -255,18 +269,22 @@ func (p *Printer) printStringMappingType(t *Type) {

func (p *Printer) printEnumLiteral(t *Type) {
if parent := p.c.getParentOfSymbol(t.symbol); parent != nil {
p.printName(parent)
p.print(".")
p.printQualifiedName(parent)
if p.c.getDeclaredTypeOfSymbol(parent) != t {
p.print(".")
p.printName(t.symbol)
}
return
}
p.printName(t.symbol)
p.printQualifiedName(t.symbol)
}

func (p *Printer) printObjectType(t *Type) {
switch {
case t.objectFlags&ObjectFlagsReference != 0:
p.printParameterizedType(t)
case t.objectFlags&ObjectFlagsClassOrInterface != 0:
p.printName(t.symbol)
p.printQualifiedName(t.symbol)
case p.c.isGenericMappedType(t) || t.objectFlags&ObjectFlagsMapped != 0 && t.AsMappedType().containsError:
p.printMappedType(t)
default:
Expand All @@ -286,7 +304,7 @@ func (p *Printer) printParameterizedType(t *Type) {
}

func (p *Printer) printTypeReference(t *Type) {
p.printName(t.symbol)
p.printQualifiedName(t.symbol)
p.printTypeArguments(p.c.getTypeArguments(t)[:p.c.getTypeReferenceArity(t)])
}

Expand Down Expand Up @@ -360,13 +378,7 @@ func (p *Printer) printAnonymousType(t *Type) {
if t.symbol.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsEnum|ast.SymbolFlagsValueModule) != 0 {
if t == p.c.getTypeOfSymbol(t.symbol) {
p.print("typeof ")
if t.symbol.Flags&ast.SymbolFlagsValueModule != 0 && t.symbol.Name[0] == '"' {
p.print("import(")
p.print(t.symbol.Name)
p.print(")")
} else {
p.printName(t.symbol)
}
p.printQualifiedName(t.symbol)
return
}
}
Expand Down Expand Up @@ -515,7 +527,7 @@ func (p *Printer) printUnionType(t *Type) {
case t.flags&TypeFlagsBoolean != 0:
p.print("boolean")
case t.flags&TypeFlagsEnumLiteral != 0:
p.printName(t.symbol)
p.printQualifiedName(t.symbol)
default:
u := t.AsUnionType()
if u.origin != nil {
Expand Down
53 changes: 39 additions & 14 deletions internal/checker/relater.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,12 @@ func (c *Checker) checkTypeRelatedToEx(
headMessage *diagnostics.Message,
diagnosticOutput *[]*ast.Diagnostic,
) bool {
relaterCount := len(c.relaters)
c.relaters = slices.Grow(c.relaters, 1)[:relaterCount+1]
r := &c.relaters[relaterCount]
r.c = c
r := c.freeRelater
if r == nil {
r = &Relater{c: c}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I feel like we should probably clean this up into a plain sync pool, but, not in this PR.

} else {
c.freeRelater = r.next
}
r.relation = relation
r.errorNode = errorNode
r.relationCount = (16_000_000 - relation.size()) / 8
Expand Down Expand Up @@ -396,14 +398,16 @@ func (c *Checker) checkTypeRelatedToEx(
}
c.reportDiagnostic(createDiagnosticChainFromErrorChain(r.errorChain, r.errorNode, r.relatedInfo), diagnosticOutput)
}
c.relaters = c.relaters[:relaterCount]
r.maybeKeysSet.Clear()
*r = Relater{
c: c,
maybeKeys: r.maybeKeys[:0],
maybeKeysSet: r.maybeKeysSet,
sourceStack: r.sourceStack[:0],
targetStack: r.targetStack[:0],
next: c.freeRelater,
}
c.freeRelater = r
return result != TernaryFalse
}

Expand Down Expand Up @@ -2521,6 +2525,7 @@ type Relater struct {
expandingFlags ExpandingFlags
overflow bool
relationCount int
next *Relater
}

func (r *Relater) isRelatedToSimple(source *Type, target *Type) Ternary {
Expand Down Expand Up @@ -4265,18 +4270,20 @@ func (r *Relater) reportUnmatchedProperty(source *Type, target *Type, unmatchedP
}
props := r.c.getUnmatchedProperties(source, target, requireOptionalProperties, false /*matchDiscriminantProperties*/)
if len(props) == 1 {
sourceType, targetType := r.c.getTypeNamesForErrorDisplay(source, target)
propName := r.c.symbolToString(unmatchedProperty)
r.reportError(diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, r.c.TypeToString(source), r.c.TypeToString(target))
r.reportError(diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, sourceType, targetType)
if len(unmatchedProperty.Declarations) != 0 {
r.relatedInfo = append(r.relatedInfo, createDiagnosticForNode(unmatchedProperty.Declarations[0], diagnostics.X_0_is_declared_here, propName))
}
} else if r.tryElaborateArrayLikeErrors(source, target, false /*reportErrors*/) {
sourceType, targetType := r.c.getTypeNamesForErrorDisplay(source, target)
if len(props) > 5 {
propNames := strings.Join(core.Map(props[:4], r.c.symbolToString), ", ")
r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, r.c.TypeToString(source), r.c.TypeToString(target), propNames, len(props)-4)
r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, sourceType, targetType, propNames, len(props)-4)
} else {
propNames := strings.Join(core.Map(props, r.c.symbolToString), ", ")
r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, r.c.TypeToString(source), r.c.TypeToString(target), propNames)
r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, sourceType, targetType, propNames)
}
}
}
Expand Down Expand Up @@ -4677,6 +4684,7 @@ func (r *Relater) reportRelationError(message *diagnostics.Message, source *Type
case constraint != nil && r.c.isTypeAssignableTo(source, constraint):
r.reportError(diagnostics.X_0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, sourceType, targetType, r.c.TypeToString(constraint))
default:
r.errorChain = nil // Only report this error once
r.reportError(diagnostics.X_0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, targetType, generalizedSourceType)
}
}
Expand Down Expand Up @@ -4755,12 +4763,7 @@ func (r *Relater) reportError(message *diagnostics.Message, args ...any) {
diagnostics.The_types_returned_by_0_are_incompatible_between_these_types:
head := getPropertyNameArg(args[0])
tail := getPropertyNameArg(r.errorChain.next.args[0])
var arg string
if len(tail) != 0 && tail[0] == '[' {
arg = head + tail
} else {
arg = head + "." + tail
}
arg := addToDottedName(head, tail)
r.errorChain = r.errorChain.next.next
if message == diagnostics.Types_of_property_0_are_incompatible {
message = diagnostics.The_types_of_0_are_incompatible_between_these_types
Expand All @@ -4772,6 +4775,28 @@ func (r *Relater) reportError(message *diagnostics.Message, args ...any) {
r.errorChain = &ErrorChain{next: r.errorChain, message: message, args: args}
}

func addToDottedName(head string, tail string) string {
if strings.HasPrefix(head, "new ") {
head = "(" + head + ")"
}
pos := 0
for {
if strings.HasPrefix(tail[pos:], "(") {
pos++
} else if strings.HasPrefix(tail[pos:], "new ") {
pos += 4
} else {
break
}
}
prefix := tail[:pos]
suffix := tail[pos:]
if strings.HasPrefix(suffix, "[") {
return prefix + head + suffix
}
return prefix + head + "." + suffix
}

func (r *Relater) getChainMessage(index int) *diagnostics.Message {
e := r.errorChain
for {
Expand Down
4 changes: 1 addition & 3 deletions internal/jsnum/jsnum.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,10 @@ func (n Number) Remainder(d Number) Number {
case n == 0:
return n
}

r := n - d*(n/d).trunc()
if r == 0 || n < 0 {
if r == 0 && n < 0 {
return negativeZero
}

return r
}

Expand Down
Loading