Skip to content

Commit 30a2e24

Browse files
authored
More type checking + bug fixes (#415)
1 parent 63932c7 commit 30a2e24

File tree

1 file changed

+86
-9
lines changed

1 file changed

+86
-9
lines changed

internal/checker/checker.go

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5462,7 +5462,7 @@ func (c *Checker) checkVariableLikeDeclaration(node *ast.Node) {
54625462
if ast.IsVariableDeclaration(node) || ast.IsBindingElement(node) {
54635463
c.checkVarDeclaredNamesNotShadowed(node)
54645464
}
5465-
// !!! c.checkCollisionsForDeclarationName(node, node.Name)
5465+
c.checkCollisionsForDeclarationName(node, node.Name())
54665466
}
54675467
}
54685468

@@ -6540,7 +6540,7 @@ func (c *Checker) reportUnusedBindingElements(node *ast.Node) {
65406540
func (c *Checker) reportUnusedVariableDeclarations(declarations []*ast.Node) {
65416541
for _, declaration := range declarations {
65426542
name := declaration.Name()
6543-
if name != nil {
6543+
if name != nil && !ast.IsParameterPropertyDeclaration(declaration, declaration.Parent) && !ast.IsThisParameter(declaration) {
65446544
if ast.IsBindingPattern(name) {
65456545
c.reportUnusedBindingElements(name)
65466546
} else if c.isUnreferencedVariableDeclaration(declaration) {
@@ -9686,7 +9686,14 @@ func (c *Checker) assignBindingElementTypes(pattern *ast.Node, parentType *Type)
96869686
}
96879687

96889688
func (c *Checker) checkCollisionsForDeclarationName(node *ast.Node, name *ast.Node) {
9689-
// !!!
9689+
switch {
9690+
case name == nil:
9691+
return
9692+
case ast.IsClassLike(node):
9693+
c.checkTypeNameIsReserved(name, diagnostics.Class_name_cannot_be_0)
9694+
case ast.IsEnumDeclaration(node):
9695+
c.checkTypeNameIsReserved(name, diagnostics.Enum_name_cannot_be_0)
9696+
}
96909697
}
96919698

96929699
func (c *Checker) checkTypeOfExpression(node *ast.Node) *Type {
@@ -10739,7 +10746,47 @@ func (c *Checker) isUncalledFunctionReference(node *ast.Node, symbol *ast.Symbol
1073910746
}
1074010747

1074110748
func (c *Checker) checkPropertyNotUsedBeforeDeclaration(prop *ast.Symbol, node *ast.Node, right *ast.Node) {
10742-
// !!!
10749+
valueDeclaration := prop.ValueDeclaration
10750+
if valueDeclaration == nil || ast.GetSourceFileOfNode(node).IsDeclarationFile {
10751+
return
10752+
}
10753+
var diagnostic *ast.Diagnostic
10754+
declarationName := right.Text()
10755+
if c.isInPropertyInitializerOrClassStaticBlock(node) &&
10756+
!c.isOptionalPropertyDeclaration(valueDeclaration) &&
10757+
!(ast.IsAccessExpression(node) && ast.IsAccessExpression(node.Expression())) &&
10758+
!c.isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) &&
10759+
!(ast.IsMethodDeclaration(valueDeclaration) && c.getCombinedModifierFlagsCached(valueDeclaration)&ast.ModifierFlagsStatic != 0) &&
10760+
(c.compilerOptions.UseDefineForClassFields.IsTrue() || !c.isPropertyDeclaredInAncestorClass(prop)) {
10761+
diagnostic = c.error(right, diagnostics.Property_0_is_used_before_its_initialization, declarationName)
10762+
} else if ast.IsClassDeclaration(valueDeclaration) && ast.IsTypeReferenceNode(node.Parent) && valueDeclaration.Flags&ast.NodeFlagsAmbient == 0 && !c.isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) {
10763+
diagnostic = c.error(right, diagnostics.Class_0_used_before_its_declaration, declarationName)
10764+
}
10765+
if diagnostic != nil {
10766+
diagnostic.AddRelatedInfo(NewDiagnosticForNode(valueDeclaration, diagnostics.X_0_is_declared_here, declarationName))
10767+
}
10768+
}
10769+
10770+
func (c *Checker) isOptionalPropertyDeclaration(node *ast.Node) bool {
10771+
return ast.IsPropertyDeclaration(node) && !ast.HasAccessorModifier(node) && ast.IsQuestionToken(node.AsPropertyDeclaration().PostfixToken)
10772+
}
10773+
10774+
func (c *Checker) isPropertyDeclaredInAncestorClass(prop *ast.Symbol) bool {
10775+
if prop.Parent.Flags&ast.SymbolFlagsClass == 0 {
10776+
return false
10777+
}
10778+
classType := c.getDeclaredTypeOfSymbol(prop.Parent)
10779+
for {
10780+
baseTypes := c.getBaseTypes(classType)
10781+
if len(baseTypes) == 0 {
10782+
return false
10783+
}
10784+
classType = baseTypes[0]
10785+
superProperty := c.getPropertyOfType(classType, prop.Name)
10786+
if superProperty != nil && superProperty.ValueDeclaration != nil {
10787+
return true
10788+
}
10789+
}
1074310790
}
1074410791

1074510792
/**
@@ -26834,7 +26881,7 @@ func (c *Checker) getContextualTypeForBindingElement(declaration *ast.Node, cont
2683426881
parent := declaration.Parent.Parent
2683526882
parentType := c.getContextualTypeForVariableLikeDeclaration(parent, contextFlags)
2683626883
if parentType == nil {
26837-
if ast.IsBindingElement(parent) && parent.Initializer() != nil {
26884+
if !ast.IsBindingElement(parent) && parent.Initializer() != nil {
2683826885
parentType = c.checkDeclarationInitializer(parent, core.IfElse(hasDotDotDotToken(declaration), CheckModeRestBindingElement, CheckModeNormal), nil)
2683926886
}
2684026887
}
@@ -27057,7 +27104,7 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags
2705727104
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
2705827105
// If the binary operator has a symbol, this is an assignment declaration and there is no contextual type.
2705927106
if node == binary.Right && binary.Symbol == nil {
27060-
return c.getTypeOfExpression(binary.Left)
27107+
return c.getContextualTypeFromAssignmentTarget(binary.Left)
2706127108
}
2706227109
case ast.KindBarBarToken, ast.KindQuestionQuestionToken:
2706327110
// When an || expression has a contextual type, the operands are contextually typed by that type, except
@@ -27078,6 +27125,33 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags
2707827125
return nil
2707927126
}
2708027127

27128+
func (c *Checker) getContextualTypeFromAssignmentTarget(node *ast.Node) *Type {
27129+
if ast.IsAccessExpression(node) && node.Expression().Kind == ast.KindThisKeyword {
27130+
var symbol *ast.Symbol
27131+
if ast.IsPropertyAccessExpression(node) {
27132+
name := node.Name()
27133+
thisType := c.getTypeOfExpression(node.Expression())
27134+
if ast.IsPrivateIdentifier(name) {
27135+
symbol = c.getPropertyOfType(thisType, binder.GetSymbolNameForPrivateIdentifier(thisType.symbol, name.Text()))
27136+
} else {
27137+
symbol = c.getPropertyOfType(thisType, name.Text())
27138+
}
27139+
} else {
27140+
propType := c.checkExpressionCached(node.AsElementAccessExpression().ArgumentExpression)
27141+
if isTypeUsableAsPropertyName(propType) {
27142+
symbol = c.getPropertyOfType(c.getTypeOfExpression(node.Expression()), getPropertyNameFromType(propType))
27143+
}
27144+
}
27145+
if symbol != nil {
27146+
d := symbol.ValueDeclaration
27147+
if d != nil && (ast.IsPropertyDeclaration(d) || ast.IsPropertySignatureDeclaration(d)) && d.Type() == nil && d.Initializer() == nil {
27148+
return nil
27149+
}
27150+
}
27151+
}
27152+
return c.getTypeOfExpression(node)
27153+
}
27154+
2708127155
func (c *Checker) getContextualTypeForObjectLiteralElement(element *ast.Node, contextFlags ContextFlags) *Type {
2708227156
objectLiteral := element.Parent
2708327157
t := c.getApparentTypeOfContextualType(objectLiteral, contextFlags)
@@ -27544,16 +27618,19 @@ func (c *Checker) getESDecoratorCallSignature(decorator *ast.Node) *Signature {
2754427618
// runtime-generated getter and setter that are added to the class/prototype. The `target` of a
2754527619
// regular field decorator is always `undefined` as it isn't installed until it is initialized.
2754627620
var targetType *Type
27621+
if ast.HasAccessorModifier(node) {
27622+
targetType = c.newClassAccessorDecoratorTargetType(thisType, valueType)
27623+
} else {
27624+
targetType = c.undefinedType
27625+
}
2754727626
// We wrap the "output type" depending on the declaration. For auto-accessors, we wrap the
2754827627
// "output type" in a `ClassAccessorDecoratorResult<This, In, Out>` type, which allows for
2754927628
// mutation of the runtime-generated getter and setter, as well as the injection of an
2755027629
// initializer mutator. For regular fields, we wrap the "output type" in an initializer mutator.
2755127630
var returnType *Type
2755227631
if ast.HasAccessorModifier(node) {
27553-
targetType = c.newClassAccessorDecoratorTargetType(thisType, valueType)
27554-
returnType = targetType
27632+
returnType = c.newClassAccessorDecoratorResultType(thisType, valueType)
2755527633
} else {
27556-
targetType = c.undefinedType
2755727634
returnType = c.newClassFieldDecoratorInitializerMutatorType(thisType, valueType)
2755827635
}
2755927636
contextType := c.newClassMemberDecoratorContextTypeForNode(node, thisType, valueType)

0 commit comments

Comments
 (0)