remove unused packages
This commit is contained in:
parent
0cea2e734b
commit
78201db012
@ -1,8 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @kittenipc:api
|
* @kittenipc:api
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,103 +0,0 @@
|
|||||||
package checker_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/bundled"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/checker"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/compiler"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/repo"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/osvfs"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/vfstest"
|
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetSymbolAtLocation(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
content := `interface Foo {
|
|
||||||
bar: string;
|
|
||||||
}
|
|
||||||
declare const foo: Foo;
|
|
||||||
foo.bar;`
|
|
||||||
fs := vfstest.FromMap(map[string]string{
|
|
||||||
"/foo.ts": content,
|
|
||||||
"/tsconfig.json": `
|
|
||||||
{
|
|
||||||
"compilerOptions": {},
|
|
||||||
"files": ["foo.ts"]
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
}, false /*useCaseSensitiveFileNames*/)
|
|
||||||
fs = bundled.WrapFS(fs)
|
|
||||||
|
|
||||||
cd := "/"
|
|
||||||
host := compiler.NewCompilerHost(cd, fs, bundled.LibPath(), nil, nil)
|
|
||||||
|
|
||||||
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile("/tsconfig.json", &core.CompilerOptions{}, host, nil)
|
|
||||||
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
|
|
||||||
|
|
||||||
p := compiler.NewProgram(compiler.ProgramOptions{
|
|
||||||
Config: parsed,
|
|
||||||
Host: host,
|
|
||||||
})
|
|
||||||
p.BindSourceFiles()
|
|
||||||
c, done := p.GetTypeChecker(t.Context())
|
|
||||||
defer done()
|
|
||||||
file := p.GetSourceFile("/foo.ts")
|
|
||||||
interfaceId := file.Statements.Nodes[0].Name()
|
|
||||||
varId := file.Statements.Nodes[1].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].Name()
|
|
||||||
propAccess := file.Statements.Nodes[2].AsExpressionStatement().Expression
|
|
||||||
nodes := []*ast.Node{interfaceId, varId, propAccess}
|
|
||||||
for _, node := range nodes {
|
|
||||||
symbol := c.GetSymbolAtLocation(node)
|
|
||||||
if symbol == nil {
|
|
||||||
t.Fatalf("Expected symbol to be non-nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckSrcCompiler(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
repo.SkipIfNoTypeScriptSubmodule(t)
|
|
||||||
fs := osvfs.FS()
|
|
||||||
fs = bundled.WrapFS(fs)
|
|
||||||
|
|
||||||
rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")
|
|
||||||
|
|
||||||
host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)
|
|
||||||
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
|
|
||||||
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
|
|
||||||
p := compiler.NewProgram(compiler.ProgramOptions{
|
|
||||||
Config: parsed,
|
|
||||||
Host: host,
|
|
||||||
})
|
|
||||||
p.CheckSourceFiles(t.Context(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkNewChecker(b *testing.B) {
|
|
||||||
repo.SkipIfNoTypeScriptSubmodule(b)
|
|
||||||
fs := osvfs.FS()
|
|
||||||
fs = bundled.WrapFS(fs)
|
|
||||||
|
|
||||||
rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")
|
|
||||||
|
|
||||||
host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)
|
|
||||||
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
|
|
||||||
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")
|
|
||||||
p := compiler.NewProgram(compiler.ProgramOptions{
|
|
||||||
Config: parsed,
|
|
||||||
Host: host,
|
|
||||||
})
|
|
||||||
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
for b.Loop() {
|
|
||||||
checker.NewChecker(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Checker) GetStringType() *Type {
|
|
||||||
return c.stringType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetUnknownSymbol() *ast.Symbol {
|
|
||||||
return c.unknownSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetUnionType(types []*Type) *Type {
|
|
||||||
return c.getUnionType(types)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetGlobalSymbol(name string, meaning ast.SymbolFlags, diagnostic *diagnostics.Message) *ast.Symbol {
|
|
||||||
return c.getGlobalSymbol(name, meaning, diagnostic)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetMergedSymbol(symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
return c.getMergedSymbol(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TryFindAmbientModule(moduleName string) *ast.Symbol {
|
|
||||||
return c.tryFindAmbientModule(moduleName, true /* withAugmentations */)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetImmediateAliasedSymbol(symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
return c.getImmediateAliasedSymbol(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeOnlyAliasDeclaration(symbol *ast.Symbol) *ast.Node {
|
|
||||||
return c.getTypeOnlyAliasDeclaration(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) ResolveExternalModuleName(moduleSpecifier *ast.Node) *ast.Symbol {
|
|
||||||
return c.resolveExternalModuleName(moduleSpecifier, moduleSpecifier, true /*ignoreErrors*/)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) ResolveExternalModuleSymbol(moduleSymbol *ast.Symbol) *ast.Symbol {
|
|
||||||
return c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeFromTypeNode(node *ast.Node) *Type {
|
|
||||||
return c.getTypeFromTypeNode(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsArrayLikeType(t *Type) bool {
|
|
||||||
return c.isArrayLikeType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetPropertiesOfType(t *Type) []*ast.Symbol {
|
|
||||||
return c.getPropertiesOfType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetPropertyOfType(t *Type, name string) *ast.Symbol {
|
|
||||||
return c.getPropertyOfType(t, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TypeHasCallOrConstructSignatures(t *Type) bool {
|
|
||||||
return c.typeHasCallOrConstructSignatures(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if a property can be accessed in a location.
|
|
||||||
// The location is given by the `node` parameter.
|
|
||||||
// The node does not need to be a property access.
|
|
||||||
// @param node location where to check property accessibility
|
|
||||||
// @param isSuper whether to consider this a `super` property access, e.g. `super.foo`.
|
|
||||||
// @param isWrite whether this is a write access, e.g. `++foo.x`.
|
|
||||||
// @param containingType type where the property comes from.
|
|
||||||
// @param property property symbol.
|
|
||||||
func (c *Checker) IsPropertyAccessible(node *ast.Node, isSuper bool, isWrite bool, containingType *Type, property *ast.Symbol) bool {
|
|
||||||
return c.isPropertyAccessible(node, isSuper, isWrite, containingType, property)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeOfPropertyOfContextualType(t *Type, name string) *Type {
|
|
||||||
return c.getTypeOfPropertyOfContextualType(t, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDeclarationModifierFlagsFromSymbol(s *ast.Symbol) ast.ModifierFlags {
|
|
||||||
return getDeclarationModifierFlagsFromSymbol(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) WasCanceled() bool {
|
|
||||||
return c.wasCanceled
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetSignaturesOfType(t *Type, kind SignatureKind) []*Signature {
|
|
||||||
return c.getSignaturesOfType(t, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetDeclaredTypeOfSymbol(symbol *ast.Symbol) *Type {
|
|
||||||
return c.getDeclaredTypeOfSymbol(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeOfSymbol(symbol *ast.Symbol) *Type {
|
|
||||||
return c.getTypeOfSymbol(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetConstraintOfTypeParameter(typeParameter *Type) *Type {
|
|
||||||
return c.getConstraintOfTypeParameter(typeParameter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetResolutionModeOverride(node *ast.ImportAttributes, reportErrors bool) core.ResolutionMode {
|
|
||||||
return c.getResolutionModeOverride(node, reportErrors)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetEffectiveDeclarationFlags(n *ast.Node, flagsToCheck ast.ModifierFlags) ast.ModifierFlags {
|
|
||||||
return c.getEffectiveDeclarationFlags(n, flagsToCheck)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetBaseConstraintOfType(t *Type) *Type {
|
|
||||||
return c.getBaseConstraintOfType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypePredicateOfSignature(sig *Signature) *TypePredicate {
|
|
||||||
return c.getTypePredicateOfSignature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsTupleType(t *Type) bool {
|
|
||||||
return isTupleType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetReturnTypeOfSignature(sig *Signature) *Type {
|
|
||||||
return c.getReturnTypeOfSignature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) HasEffectiveRestParameter(signature *Signature) bool {
|
|
||||||
return c.hasEffectiveRestParameter(signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol *ast.Symbol) []*Type {
|
|
||||||
return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetContextualTypeForObjectLiteralElement(element *ast.Node, contextFlags ContextFlags) *Type {
|
|
||||||
return c.getContextualTypeForObjectLiteralElement(element, contextFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TypePredicateToString(t *TypePredicate) string {
|
|
||||||
return c.typePredicateToString(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetExpandedParameters(signature *Signature, skipUnionExpanding bool) [][]*ast.Symbol {
|
|
||||||
return c.getExpandedParameters(signature, skipUnionExpanding)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetResolvedSignature(node *ast.Node) *Signature {
|
|
||||||
return c.getResolvedSignature(node, nil, CheckModeNormal)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the type of the given property in the given type, or nil if no such property exists
|
|
||||||
func (c *Checker) GetTypeOfPropertyOfType(t *Type, name string) *Type {
|
|
||||||
return c.getTypeOfPropertyOfType(t, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetContextualTypeForArgumentAtIndex(node *ast.Node, argIndex int) *Type {
|
|
||||||
return c.getContextualTypeForArgumentAtIndex(node, argIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetIndexSignaturesAtLocation(node *ast.Node) []*ast.Node {
|
|
||||||
return c.getIndexSignaturesAtLocation(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetResolvedSymbol(node *ast.Node) *ast.Symbol {
|
|
||||||
return c.getResolvedSymbol(node)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,97 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Checker) checkUnmatchedJSDocParameters(node *ast.Node) {
|
|
||||||
var jsdocParameters []*ast.Node
|
|
||||||
for _, tag := range getAllJSDocTags(node) {
|
|
||||||
if tag.Kind == ast.KindJSDocParameterTag {
|
|
||||||
name := tag.AsJSDocParameterOrPropertyTag().Name()
|
|
||||||
if ast.IsIdentifier(name) && len(name.Text()) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
jsdocParameters = append(jsdocParameters, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(jsdocParameters) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isJs := ast.IsInJSFile(node)
|
|
||||||
parameters := collections.Set[string]{}
|
|
||||||
excludedParameters := collections.Set[int]{}
|
|
||||||
|
|
||||||
for i, param := range node.Parameters() {
|
|
||||||
name := param.AsParameterDeclaration().Name()
|
|
||||||
if ast.IsIdentifier(name) {
|
|
||||||
parameters.Add(name.Text())
|
|
||||||
}
|
|
||||||
if ast.IsBindingPattern(name) {
|
|
||||||
excludedParameters.Add(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.containsArgumentsReference(node) {
|
|
||||||
if isJs {
|
|
||||||
lastJSDocParamIndex := len(jsdocParameters) - 1
|
|
||||||
lastJSDocParam := jsdocParameters[lastJSDocParamIndex].AsJSDocParameterOrPropertyTag()
|
|
||||||
if lastJSDocParam == nil || !ast.IsIdentifier(lastJSDocParam.Name()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if excludedParameters.Has(lastJSDocParamIndex) || parameters.Has(lastJSDocParam.Name().Text()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if lastJSDocParam.TypeExpression == nil || lastJSDocParam.TypeExpression.Type() == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.isArrayType(c.getTypeFromTypeNode(lastJSDocParam.TypeExpression.Type())) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.error(lastJSDocParam.Name(), diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, lastJSDocParam.Name().Text())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for index, tag := range jsdocParameters {
|
|
||||||
name := tag.AsJSDocParameterOrPropertyTag().Name()
|
|
||||||
isNameFirst := tag.AsJSDocParameterOrPropertyTag().IsNameFirst
|
|
||||||
|
|
||||||
if excludedParameters.Has(index) || (ast.IsIdentifier(name) && parameters.Has(name.Text())) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ast.IsQualifiedName(name) {
|
|
||||||
if isJs {
|
|
||||||
c.error(name, diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1,
|
|
||||||
entityNameToString(name),
|
|
||||||
entityNameToString(name.AsQualifiedName().Left),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !isNameFirst {
|
|
||||||
c.errorOrSuggestion(isJs, name,
|
|
||||||
diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
|
|
||||||
name.Text(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllJSDocTags(node *ast.Node) []*ast.Node {
|
|
||||||
if node == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
jsdocs := node.JSDoc(nil)
|
|
||||||
if len(jsdocs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
lastJSDoc := jsdocs[len(jsdocs)-1].AsJSDoc()
|
|
||||||
if lastJSDoc.Tags == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return lastJSDoc.Tags.Nodes
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,294 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
|
|
||||||
// TypeMapperKind
|
|
||||||
|
|
||||||
type TypeMapperKind int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeMapperKindUnknown TypeMapperKind = iota
|
|
||||||
TypeMapperKindSimple
|
|
||||||
TypeMapperKindArray
|
|
||||||
TypeMapperKindMerged
|
|
||||||
)
|
|
||||||
|
|
||||||
// TypeMapper
|
|
||||||
|
|
||||||
type TypeMapper struct {
|
|
||||||
data TypeMapperData
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TypeMapper) Map(t *Type) *Type { return m.data.Map(t) }
|
|
||||||
func (m *TypeMapper) Kind() TypeMapperKind { return m.data.Kind() }
|
|
||||||
|
|
||||||
// TypeMapperData
|
|
||||||
|
|
||||||
type TypeMapperData interface {
|
|
||||||
Map(t *Type) *Type
|
|
||||||
Kind() TypeMapperKind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Factory functions
|
|
||||||
|
|
||||||
func newTypeMapper(sources []*Type, targets []*Type) *TypeMapper {
|
|
||||||
if len(sources) == 1 {
|
|
||||||
return newSimpleTypeMapper(sources[0], targets[0])
|
|
||||||
}
|
|
||||||
return newArrayTypeMapper(sources, targets)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) combineTypeMappers(m1 *TypeMapper, m2 *TypeMapper) *TypeMapper {
|
|
||||||
if m1 != nil {
|
|
||||||
return newCompositeTypeMapper(c, m1, m2)
|
|
||||||
}
|
|
||||||
return m2
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeTypeMappers(m1 *TypeMapper, m2 *TypeMapper) *TypeMapper {
|
|
||||||
if m1 != nil {
|
|
||||||
return newMergedTypeMapper(m1, m2)
|
|
||||||
}
|
|
||||||
return m2
|
|
||||||
}
|
|
||||||
|
|
||||||
func prependTypeMapping(source *Type, target *Type, mapper *TypeMapper) *TypeMapper {
|
|
||||||
if mapper == nil {
|
|
||||||
return newSimpleTypeMapper(source, target)
|
|
||||||
}
|
|
||||||
return newMergedTypeMapper(newSimpleTypeMapper(source, target), mapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendTypeMapping(mapper *TypeMapper, source *Type, target *Type) *TypeMapper {
|
|
||||||
if mapper == nil {
|
|
||||||
return newSimpleTypeMapper(source, target)
|
|
||||||
}
|
|
||||||
return newMergedTypeMapper(mapper, newSimpleTypeMapper(source, target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps forward-references to later types parameters to the empty object type.
|
|
||||||
// This is used during inference when instantiating type parameter defaults.
|
|
||||||
func (c *Checker) newBackreferenceMapper(context *InferenceContext, index int) *TypeMapper {
|
|
||||||
forwardInferences := context.inferences[index:]
|
|
||||||
typeParameters := core.Map(forwardInferences, func(i *InferenceInfo) *Type {
|
|
||||||
return i.typeParameter
|
|
||||||
})
|
|
||||||
return newArrayToSingleTypeMapper(typeParameters, c.unknownType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeMapperBase
|
|
||||||
|
|
||||||
type TypeMapperBase struct {
|
|
||||||
TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TypeMapperBase) Map(t *Type) *Type { return t }
|
|
||||||
func (m *TypeMapperBase) Kind() TypeMapperKind { return TypeMapperKindUnknown }
|
|
||||||
|
|
||||||
// SimpleTypeMapper
|
|
||||||
|
|
||||||
type SimpleTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
source *Type
|
|
||||||
target *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSimpleTypeMapper(source *Type, target *Type) *TypeMapper {
|
|
||||||
m := &SimpleTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.source = source
|
|
||||||
m.target = target
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SimpleTypeMapper) Map(t *Type) *Type {
|
|
||||||
if t == m.source {
|
|
||||||
return m.target
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SimpleTypeMapper) Kind() TypeMapperKind {
|
|
||||||
return TypeMapperKindSimple
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayTypeMapper
|
|
||||||
|
|
||||||
type ArrayTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
sources []*Type
|
|
||||||
targets []*Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArrayTypeMapper(sources []*Type, targets []*Type) *TypeMapper {
|
|
||||||
m := &ArrayTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.sources = sources
|
|
||||||
m.targets = targets
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ArrayTypeMapper) Map(t *Type) *Type {
|
|
||||||
for i, s := range m.sources {
|
|
||||||
if t == s {
|
|
||||||
return m.targets[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ArrayTypeMapper) Kind() TypeMapperKind {
|
|
||||||
return TypeMapperKindArray
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayToSingleTypeMapper
|
|
||||||
|
|
||||||
type ArrayToSingleTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
sources []*Type
|
|
||||||
target *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArrayToSingleTypeMapper(sources []*Type, target *Type) *TypeMapper {
|
|
||||||
m := &ArrayToSingleTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.sources = sources
|
|
||||||
m.target = target
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ArrayToSingleTypeMapper) Map(t *Type) *Type {
|
|
||||||
for _, s := range m.sources {
|
|
||||||
if t == s {
|
|
||||||
return m.target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeferredTypeMapper
|
|
||||||
|
|
||||||
type DeferredTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
sources []*Type
|
|
||||||
targets []func() *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDeferredTypeMapper(sources []*Type, targets []func() *Type) *TypeMapper {
|
|
||||||
m := &DeferredTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.sources = sources
|
|
||||||
m.targets = targets
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DeferredTypeMapper) Map(t *Type) *Type {
|
|
||||||
for i, s := range m.sources {
|
|
||||||
if t == s {
|
|
||||||
return m.targets[i]()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// FunctionTypeMapper
|
|
||||||
|
|
||||||
type FunctionTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
fn func(*Type) *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFunctionTypeMapper(fn func(*Type) *Type) *TypeMapper {
|
|
||||||
m := &FunctionTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.fn = fn
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FunctionTypeMapper) Map(t *Type) *Type {
|
|
||||||
return m.fn(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergedTypeMapper
|
|
||||||
|
|
||||||
type MergedTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
m1 *TypeMapper
|
|
||||||
m2 *TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMergedTypeMapper(m1 *TypeMapper, m2 *TypeMapper) *TypeMapper {
|
|
||||||
m := &MergedTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.m1 = m1
|
|
||||||
m.m2 = m2
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MergedTypeMapper) Map(t *Type) *Type {
|
|
||||||
return m.m2.Map(m.m1.Map(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MergedTypeMapper) Kind() TypeMapperKind {
|
|
||||||
return TypeMapperKindMerged
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompositeTypeMapper
|
|
||||||
|
|
||||||
type CompositeTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
c *Checker
|
|
||||||
m1 *TypeMapper
|
|
||||||
m2 *TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCompositeTypeMapper(c *Checker, m1 *TypeMapper, m2 *TypeMapper) *TypeMapper {
|
|
||||||
m := &CompositeTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.c = c
|
|
||||||
m.m1 = m1
|
|
||||||
m.m2 = m2
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *CompositeTypeMapper) Map(t *Type) *Type {
|
|
||||||
t1 := m.m1.Map(t)
|
|
||||||
if t1 != t {
|
|
||||||
return m.c.instantiateType(t1, m.m2)
|
|
||||||
}
|
|
||||||
return m.m2.Map(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InferenceTypeMapper
|
|
||||||
|
|
||||||
type InferenceTypeMapper struct {
|
|
||||||
TypeMapperBase
|
|
||||||
c *Checker
|
|
||||||
n *InferenceContext
|
|
||||||
fixing bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) newInferenceTypeMapper(n *InferenceContext, fixing bool) *TypeMapper {
|
|
||||||
m := &InferenceTypeMapper{}
|
|
||||||
m.data = m
|
|
||||||
m.c = c
|
|
||||||
m.n = n
|
|
||||||
m.fixing = fixing
|
|
||||||
return &m.TypeMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *InferenceTypeMapper) Map(t *Type) *Type {
|
|
||||||
for i, inference := range m.n.inferences {
|
|
||||||
if t == inference.typeParameter {
|
|
||||||
if m.fixing && !inference.isFixed {
|
|
||||||
// Before we commit to a particular inference (and thus lock out any further inferences),
|
|
||||||
// we infer from any intra-expression inference sites we have collected.
|
|
||||||
m.c.inferFromIntraExpressionSites(m.n)
|
|
||||||
clearCachedInferences(m.n.inferences)
|
|
||||||
inference.isFixed = true
|
|
||||||
}
|
|
||||||
return m.c.getInferredType(m.n, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
@ -1,186 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/nodebuilder"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NodeBuilder struct {
|
|
||||||
ctxStack []*NodeBuilderContext
|
|
||||||
basicHost Host
|
|
||||||
impl *nodeBuilderImpl
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmitContext implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) EmitContext() *printer.EmitContext {
|
|
||||||
return b.impl.e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) enterContext(enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) {
|
|
||||||
b.ctxStack = append(b.ctxStack, b.impl.ctx)
|
|
||||||
b.impl.ctx = &NodeBuilderContext{
|
|
||||||
tracker: tracker,
|
|
||||||
flags: flags,
|
|
||||||
internalFlags: internalFlags,
|
|
||||||
enclosingDeclaration: enclosingDeclaration,
|
|
||||||
enclosingFile: ast.GetSourceFileOfNode(enclosingDeclaration),
|
|
||||||
inferTypeParameters: make([]*Type, 0),
|
|
||||||
symbolDepth: make(map[CompositeSymbolIdentity]int),
|
|
||||||
trackedSymbols: make([]*TrackedSymbolArgs, 0),
|
|
||||||
reverseMappedStack: make([]*ast.Symbol, 0),
|
|
||||||
enclosingSymbolTypes: make(map[ast.SymbolId]*Type),
|
|
||||||
remappedSymbolReferences: make(map[ast.SymbolId]*ast.Symbol),
|
|
||||||
}
|
|
||||||
// TODO: always provide this; see https://github.com/microsoft/typescript-go/pull/1588#pullrequestreview-3125218673
|
|
||||||
var moduleResolverHost Host
|
|
||||||
if tracker != nil {
|
|
||||||
moduleResolverHost = tracker.GetModuleSpecifierGenerationHost()
|
|
||||||
} else if internalFlags&nodebuilder.InternalFlagsDoNotIncludeSymbolChain != 0 {
|
|
||||||
moduleResolverHost = b.basicHost
|
|
||||||
}
|
|
||||||
tracker = NewSymbolTrackerImpl(b.impl.ctx, tracker, moduleResolverHost)
|
|
||||||
b.impl.ctx.tracker = tracker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) popContext() {
|
|
||||||
stackSize := len(b.ctxStack)
|
|
||||||
if stackSize == 0 {
|
|
||||||
b.impl.ctx = nil
|
|
||||||
} else {
|
|
||||||
b.impl.ctx = b.ctxStack[stackSize-1]
|
|
||||||
b.ctxStack = b.ctxStack[:stackSize-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) exitContext(result *ast.Node) *ast.Node {
|
|
||||||
b.exitContextCheck()
|
|
||||||
defer b.popContext()
|
|
||||||
if b.impl.ctx.encounteredError {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) exitContextSlice(result []*ast.Node) []*ast.Node {
|
|
||||||
b.exitContextCheck()
|
|
||||||
defer b.popContext()
|
|
||||||
if b.impl.ctx.encounteredError {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) exitContextCheck() {
|
|
||||||
if b.impl.ctx.truncating && b.impl.ctx.flags&nodebuilder.FlagsNoTruncation != 0 {
|
|
||||||
b.impl.ctx.tracker.ReportTruncationError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexInfoToIndexSignatureDeclaration implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) IndexInfoToIndexSignatureDeclaration(info *IndexInfo, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.indexInfoToIndexSignatureDeclarationHelper(info, nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeReturnTypeForSignature implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SerializeReturnTypeForSignature(signatureDeclaration *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
signature := b.impl.ch.getSignatureFromDeclaration(signatureDeclaration)
|
|
||||||
symbol := b.impl.ch.getSymbolOfDeclaration(signatureDeclaration)
|
|
||||||
returnType, ok := b.impl.ctx.enclosingSymbolTypes[ast.GetSymbolId(symbol)]
|
|
||||||
if !ok || returnType == nil {
|
|
||||||
returnType = b.impl.ch.instantiateType(b.impl.ch.getReturnTypeOfSignature(signature), b.impl.ctx.mapper)
|
|
||||||
}
|
|
||||||
return b.exitContext(b.impl.serializeInferredReturnTypeForSignature(signature, returnType))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *NodeBuilder) SerializeTypeParametersForSignature(signatureDeclaration *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
symbol := b.impl.ch.getSymbolOfDeclaration(signatureDeclaration)
|
|
||||||
typeParams := b.SymbolToTypeParameterDeclarations(symbol, enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContextSlice(typeParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeTypeForDeclaration implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SerializeTypeForDeclaration(declaration *ast.Node, symbol *ast.Symbol, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.serializeTypeForDeclaration(declaration, nil, symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeTypeForExpression implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SerializeTypeForExpression(expr *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.serializeTypeForExpression(expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureToSignatureDeclaration implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SignatureToSignatureDeclaration(signature *Signature, kind ast.Kind, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.signatureToSignatureDeclarationHelper(signature, kind, nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolTableToDeclarationStatements implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SymbolTableToDeclarationStatements(symbolTable *ast.SymbolTable, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContextSlice(b.impl.symbolTableToDeclarationStatements(symbolTable))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolToEntityName implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SymbolToEntityName(symbol *ast.Symbol, meaning ast.SymbolFlags, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.symbolToName(symbol, meaning, false))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolToExpression implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SymbolToExpression(symbol *ast.Symbol, meaning ast.SymbolFlags, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.symbolToExpression(symbol, meaning))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolToNode implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SymbolToNode(symbol *ast.Symbol, meaning ast.SymbolFlags, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.symbolToNode(symbol, meaning))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolToParameterDeclaration implements NodeBuilderInterface.
|
|
||||||
func (b NodeBuilder) SymbolToParameterDeclaration(symbol *ast.Symbol, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.symbolToParameterDeclaration(symbol, false))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SymbolToTypeParameterDeclarations implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) SymbolToTypeParameterDeclarations(symbol *ast.Symbol, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContextSlice(b.impl.symbolToTypeParameterDeclarations(symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeParameterToDeclaration implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) TypeParameterToDeclaration(parameter *Type, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.typeParameterToDeclaration(parameter))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypePredicateToTypePredicateNode implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) TypePredicateToTypePredicateNode(predicate *TypePredicate, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.typePredicateToTypePredicateNode(predicate))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeToTypeNode implements NodeBuilderInterface.
|
|
||||||
func (b *NodeBuilder) TypeToTypeNode(typ *Type, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
|
|
||||||
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
|
|
||||||
return b.exitContext(b.impl.typeToTypeNode(typ))
|
|
||||||
}
|
|
||||||
|
|
||||||
// var _ NodeBuilderInterface = NewNodeBuilderAPI(nil, nil)
|
|
||||||
|
|
||||||
func NewNodeBuilder(ch *Checker, e *printer.EmitContext) *NodeBuilder {
|
|
||||||
impl := newNodeBuilderImpl(ch, e)
|
|
||||||
return &NodeBuilder{impl: impl, ctxStack: make([]*NodeBuilderContext, 0, 1), basicHost: ch.program}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getNodeBuilder() *NodeBuilder {
|
|
||||||
return NewNodeBuilder(c, printer.NewEmitContext())
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,246 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"maps"
|
|
||||||
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/nodebuilder"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cloneNodeBuilderContext(context *NodeBuilderContext) func() {
|
|
||||||
// Make type parameters created within this context not consume the name outside this context
|
|
||||||
// The symbol serializer ends up creating many sibling scopes that all need "separate" contexts when
|
|
||||||
// it comes to naming things - within a normal `typeToTypeNode` call, the node builder only ever descends
|
|
||||||
// through the type tree, so the only cases where we could have used distinct sibling scopes was when there
|
|
||||||
// were multiple generic overloads with similar generated type parameter names
|
|
||||||
// The effect:
|
|
||||||
// When we write out
|
|
||||||
// export const x: <T>(x: T) => T
|
|
||||||
// export const y: <T>(x: T) => T
|
|
||||||
// we write it out like that, rather than as
|
|
||||||
// export const x: <T>(x: T) => T
|
|
||||||
// export const y: <T_1>(x: T_1) => T_1
|
|
||||||
oldMustCreateTypeParameterSymbolList := context.hasCreatedTypeParameterSymbolList
|
|
||||||
oldMustCreateTypeParametersNamesLookups := context.hasCreatedTypeParametersNamesLookups
|
|
||||||
oldTypeParameterNames := context.typeParameterNames
|
|
||||||
oldTypeParameterNamesByText := context.typeParameterNamesByText
|
|
||||||
oldTypeParameterNamesByTextNextNameCount := context.typeParameterNamesByTextNextNameCount
|
|
||||||
oldTypeParameterSymbolList := context.typeParameterSymbolList
|
|
||||||
context.hasCreatedTypeParameterSymbolList = oldTypeParameterSymbolList != nil
|
|
||||||
context.hasCreatedTypeParametersNamesLookups = oldTypeParameterNames != nil
|
|
||||||
context.typeParameterNames = maps.Clone(context.typeParameterNames)
|
|
||||||
context.typeParameterNamesByText = maps.Clone(context.typeParameterNamesByText)
|
|
||||||
context.typeParameterNamesByTextNextNameCount = maps.Clone(context.typeParameterNamesByTextNextNameCount)
|
|
||||||
context.typeParameterSymbolList = maps.Clone(context.typeParameterSymbolList)
|
|
||||||
return func() {
|
|
||||||
context.typeParameterNames = oldTypeParameterNames
|
|
||||||
context.typeParameterNamesByText = oldTypeParameterNamesByText
|
|
||||||
context.typeParameterNamesByTextNextNameCount = oldTypeParameterNamesByTextNextNameCount
|
|
||||||
context.typeParameterSymbolList = oldTypeParameterSymbolList
|
|
||||||
context.hasCreatedTypeParameterSymbolList = oldMustCreateTypeParameterSymbolList
|
|
||||||
context.hasCreatedTypeParametersNamesLookups = oldMustCreateTypeParametersNamesLookups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type localsRecord struct {
|
|
||||||
name string
|
|
||||||
oldSymbol *ast.Symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *nodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams []*ast.Symbol, typeParameters []*Type, originalParameters []*ast.Symbol, mapper *TypeMapper) func() {
|
|
||||||
cleanupContext := cloneNodeBuilderContext(b.ctx)
|
|
||||||
// For regular function/method declarations, the enclosing declaration will already be signature.declaration,
|
|
||||||
// so this is a no-op, but for arrow functions and function expressions, the enclosing declaration will be
|
|
||||||
// the declaration that the arrow function / function expression is assigned to.
|
|
||||||
//
|
|
||||||
// If the parameters or return type include "typeof globalThis.paramName", using the wrong scope will lead
|
|
||||||
// us to believe that we can emit "typeof paramName" instead, even though that would refer to the parameter,
|
|
||||||
// not the global. Make sure we are in the right scope by changing the enclosingDeclaration to the function.
|
|
||||||
//
|
|
||||||
// We can't use the declaration directly; it may be in another file and so we may lose access to symbols
|
|
||||||
// accessible to the current enclosing declaration, or gain access to symbols not accessible to the current
|
|
||||||
// enclosing declaration. To keep this chain accurate, insert a fake scope into the chain which makes the
|
|
||||||
// function's parameters visible.
|
|
||||||
var cleanupParams func()
|
|
||||||
var cleanupTypeParams func()
|
|
||||||
oldEnclosingDecl := b.ctx.enclosingDeclaration
|
|
||||||
oldMapper := b.ctx.mapper
|
|
||||||
if mapper != nil {
|
|
||||||
b.ctx.mapper = mapper
|
|
||||||
}
|
|
||||||
if b.ctx.enclosingDeclaration != nil && declaration != nil {
|
|
||||||
// As a performance optimization, reuse the same fake scope within this chain.
|
|
||||||
// This is especially needed when we are working on an excessively deep type;
|
|
||||||
// if we don't do this, then we spend all of our time adding more and more
|
|
||||||
// scopes that need to be searched in isSymbolAccessible later. Since all we
|
|
||||||
// really want to do is to mark certain names as unavailable, we can just keep
|
|
||||||
// all of the names we're introducing in one large table and push/pop from it as
|
|
||||||
// needed; isSymbolAccessible will walk upward and find the closest "fake" scope,
|
|
||||||
// which will conveniently report on any and all faked scopes in the chain.
|
|
||||||
//
|
|
||||||
// It'd likely be better to store this somewhere else for isSymbolAccessible, but
|
|
||||||
// since that API _only_ uses the enclosing declaration (and its parents), this is
|
|
||||||
// seems like the best way to inject names into that search process.
|
|
||||||
//
|
|
||||||
// Note that we only check the most immediate enclosingDeclaration; the only place we
|
|
||||||
// could potentially add another fake scope into the chain is right here, so we don't
|
|
||||||
// traverse all ancestors.
|
|
||||||
pushFakeScope := func(kind string, addAll func(addSymbol func(name string, symbol *ast.Symbol))) func() {
|
|
||||||
// We only ever need to look two declarations upward.
|
|
||||||
debug.AssertIsDefined(b.ctx.enclosingDeclaration)
|
|
||||||
var existingFakeScope *ast.Node
|
|
||||||
if b.links.Has(b.ctx.enclosingDeclaration) {
|
|
||||||
links := b.links.Get(b.ctx.enclosingDeclaration)
|
|
||||||
if links.fakeScopeForSignatureDeclaration != nil && *links.fakeScopeForSignatureDeclaration == kind {
|
|
||||||
existingFakeScope = b.ctx.enclosingDeclaration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if existingFakeScope == nil && b.ctx.enclosingDeclaration.Parent != nil {
|
|
||||||
if b.links.Has(b.ctx.enclosingDeclaration.Parent) {
|
|
||||||
links := b.links.Get(b.ctx.enclosingDeclaration.Parent)
|
|
||||||
if links.fakeScopeForSignatureDeclaration != nil && *links.fakeScopeForSignatureDeclaration == kind {
|
|
||||||
existingFakeScope = b.ctx.enclosingDeclaration.Parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug.AssertOptionalNode(existingFakeScope, ast.IsBlock)
|
|
||||||
|
|
||||||
var locals ast.SymbolTable
|
|
||||||
if existingFakeScope != nil {
|
|
||||||
locals = existingFakeScope.Locals()
|
|
||||||
}
|
|
||||||
if locals == nil {
|
|
||||||
locals = make(ast.SymbolTable)
|
|
||||||
}
|
|
||||||
newLocals := []string{}
|
|
||||||
oldLocals := []localsRecord{}
|
|
||||||
addAll(func(name string, symbol *ast.Symbol) {
|
|
||||||
// Add cleanup information only if we don't own the fake scope
|
|
||||||
if existingFakeScope != nil {
|
|
||||||
oldSymbol, ok := locals[name]
|
|
||||||
if !ok || oldSymbol == nil {
|
|
||||||
newLocals = append(newLocals, name)
|
|
||||||
} else {
|
|
||||||
oldLocals = append(oldLocals, localsRecord{name, oldSymbol})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
locals[name] = symbol
|
|
||||||
})
|
|
||||||
|
|
||||||
if existingFakeScope == nil {
|
|
||||||
// Use a Block for this; the type of the node doesn't matter so long as it
|
|
||||||
// has locals, and this is cheaper/easier than using a function-ish Node.
|
|
||||||
fakeScope := b.f.NewBlock(b.f.NewNodeList([]*ast.Node{}), false)
|
|
||||||
b.links.Get(fakeScope).fakeScopeForSignatureDeclaration = &kind
|
|
||||||
data := fakeScope.LocalsContainerData()
|
|
||||||
data.Locals = locals
|
|
||||||
fakeScope.Parent = b.ctx.enclosingDeclaration
|
|
||||||
b.ctx.enclosingDeclaration = fakeScope
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
// We did not create the current scope, so we have to clean it up
|
|
||||||
undo := func() {
|
|
||||||
for _, s := range newLocals {
|
|
||||||
delete(locals, s)
|
|
||||||
}
|
|
||||||
for _, s := range oldLocals {
|
|
||||||
locals[s.name] = s.oldSymbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if expandedParams == nil || !core.Some(expandedParams, func(p *ast.Symbol) bool { return p != nil }) {
|
|
||||||
cleanupParams = nil
|
|
||||||
} else {
|
|
||||||
cleanupParams = pushFakeScope("params", func(add func(name string, symbol *ast.Symbol)) {
|
|
||||||
if expandedParams == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for pIndex, param := range expandedParams {
|
|
||||||
var originalParam *ast.Symbol
|
|
||||||
if pIndex < len(originalParameters) {
|
|
||||||
originalParam = (originalParameters)[pIndex]
|
|
||||||
}
|
|
||||||
if originalParameters != nil && originalParam != param {
|
|
||||||
// Can't reference parameters that come from an expansion
|
|
||||||
add(param.Name, b.ch.unknownSymbol)
|
|
||||||
// Can't reference the original expanded parameter either
|
|
||||||
if originalParam != nil {
|
|
||||||
add(originalParam.Name, b.ch.unknownSymbol)
|
|
||||||
}
|
|
||||||
} else if !core.Some(param.Declarations, func(d *ast.Node) bool {
|
|
||||||
var bindElement func(e *ast.BindingElement)
|
|
||||||
var bindPattern func(e *ast.BindingPattern)
|
|
||||||
|
|
||||||
bindPatternWorker := func(p *ast.BindingPattern) {
|
|
||||||
for _, e := range p.Elements.Nodes {
|
|
||||||
switch e.Kind {
|
|
||||||
case ast.KindOmittedExpression:
|
|
||||||
return
|
|
||||||
case ast.KindBindingElement:
|
|
||||||
bindElement(e.AsBindingElement())
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
panic("Unhandled binding element kind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bindElementWorker := func(e *ast.BindingElement) {
|
|
||||||
if e.Name() != nil && ast.IsBindingPattern(e.Name()) {
|
|
||||||
bindPattern(e.Name().AsBindingPattern())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
symbol := b.ch.getSymbolOfDeclaration(e.AsNode())
|
|
||||||
if symbol != nil { // omitted expressions are now parsed as nameless binding patterns and also have no symbol
|
|
||||||
add(symbol.Name, symbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bindElement = bindElementWorker
|
|
||||||
bindPattern = bindPatternWorker
|
|
||||||
|
|
||||||
if ast.IsParameter(d) && d.Name() != nil && ast.IsBindingPattern(d.Name()) {
|
|
||||||
bindPattern(d.Name().AsBindingPattern())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}) {
|
|
||||||
add(param.Name, param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.ctx.flags&nodebuilder.FlagsGenerateNamesForShadowedTypeParams != 0 && typeParameters != nil && core.Some(typeParameters, func(p *Type) bool { return p != nil }) {
|
|
||||||
cleanupTypeParams = pushFakeScope("typeParams", func(add func(name string, symbol *ast.Symbol)) {
|
|
||||||
if typeParameters == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, typeParam := range typeParameters {
|
|
||||||
if typeParam == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
typeParamName := b.typeParameterToName(typeParam).Text
|
|
||||||
add(typeParamName, typeParam.symbol)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return func() {
|
|
||||||
if cleanupParams != nil {
|
|
||||||
cleanupParams()
|
|
||||||
}
|
|
||||||
if cleanupTypeParams != nil {
|
|
||||||
cleanupTypeParams()
|
|
||||||
}
|
|
||||||
cleanupContext()
|
|
||||||
b.ctx.enclosingDeclaration = oldEnclosingDecl
|
|
||||||
b.ctx.mapper = oldMapper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,379 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/nodebuilder"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: Memoize once per checker to retain threadsafety
|
|
||||||
func createPrinterWithDefaults(emitContext *printer.EmitContext) *printer.Printer {
|
|
||||||
return printer.NewPrinter(printer.PrinterOptions{}, printer.PrintHandlers{}, emitContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPrinterWithRemoveComments(emitContext *printer.EmitContext) *printer.Printer {
|
|
||||||
return printer.NewPrinter(printer.PrinterOptions{RemoveComments: true}, printer.PrintHandlers{}, emitContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPrinterWithRemoveCommentsOmitTrailingSemicolon(emitContext *printer.EmitContext) *printer.Printer {
|
|
||||||
// TODO: OmitTrailingSemicolon support
|
|
||||||
return printer.NewPrinter(printer.PrinterOptions{RemoveComments: true}, printer.PrintHandlers{}, emitContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPrinterWithRemoveCommentsNeverAsciiEscape(emitContext *printer.EmitContext) *printer.Printer {
|
|
||||||
return printer.NewPrinter(printer.PrinterOptions{
|
|
||||||
RemoveComments: true,
|
|
||||||
NeverAsciiEscape: true,
|
|
||||||
}, printer.PrintHandlers{}, emitContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
type semicolonRemoverWriter struct {
|
|
||||||
hasPendingSemicolon bool
|
|
||||||
inner printer.EmitTextWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) commitSemicolon() {
|
|
||||||
if s.hasPendingSemicolon {
|
|
||||||
s.inner.WriteTrailingSemicolon(";")
|
|
||||||
s.hasPendingSemicolon = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) Clear() {
|
|
||||||
s.inner.Clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) DecreaseIndent() {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.DecreaseIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) GetColumn() int {
|
|
||||||
return s.inner.GetColumn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) GetIndent() int {
|
|
||||||
return s.inner.GetIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) GetLine() int {
|
|
||||||
return s.inner.GetLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) GetTextPos() int {
|
|
||||||
return s.inner.GetTextPos()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) HasTrailingComment() bool {
|
|
||||||
return s.inner.HasTrailingComment()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) HasTrailingWhitespace() bool {
|
|
||||||
return s.inner.HasTrailingWhitespace()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) IncreaseIndent() {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.IncreaseIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) IsAtStartOfLine() bool {
|
|
||||||
return s.inner.IsAtStartOfLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) RawWrite(s1 string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.RawWrite(s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) String() string {
|
|
||||||
s.commitSemicolon()
|
|
||||||
return s.inner.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) Write(s1 string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.Write(s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteComment(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteComment(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteKeyword(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteKeyword(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteLine() {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteLineForce(force bool) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteLineForce(force)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteLiteral(s1 string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteLiteral(s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteOperator(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteOperator(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteParameter(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteParameter(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteProperty(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteProperty(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WritePunctuation(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WritePunctuation(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteSpace(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteSpace(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteStringLiteral(text string) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteStringLiteral(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteSymbol(text string, symbol *ast.Symbol) {
|
|
||||||
s.commitSemicolon()
|
|
||||||
s.inner.WriteSymbol(text, symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *semicolonRemoverWriter) WriteTrailingSemicolon(text string) {
|
|
||||||
s.hasPendingSemicolon = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTrailingSemicolonDeferringWriter(writer printer.EmitTextWriter) printer.EmitTextWriter {
|
|
||||||
return &semicolonRemoverWriter{false, writer}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TypeToString(t *Type) string {
|
|
||||||
return c.typeToString(t, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) typeToString(t *Type, enclosingDeclaration *ast.Node) string {
|
|
||||||
return c.typeToStringEx(t, enclosingDeclaration, TypeFormatFlagsAllowUniqueESSymbolType|TypeFormatFlagsUseAliasDefinedOutsideCurrentScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toNodeBuilderFlags(flags TypeFormatFlags) nodebuilder.Flags {
|
|
||||||
return nodebuilder.Flags(flags & TypeFormatFlagsNodeBuilderFlagsMask)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TypeToStringEx(t *Type, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string {
|
|
||||||
return c.typeToStringEx(t, enclosingDeclaration, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) typeToStringEx(t *Type, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string {
|
|
||||||
writer := printer.NewTextWriter("")
|
|
||||||
noTruncation := (c.compilerOptions.NoErrorTruncation == core.TSTrue) || (flags&TypeFormatFlagsNoTruncation != 0)
|
|
||||||
combinedFlags := toNodeBuilderFlags(flags) | nodebuilder.FlagsIgnoreErrors
|
|
||||||
if noTruncation {
|
|
||||||
combinedFlags = combinedFlags | nodebuilder.FlagsNoTruncation
|
|
||||||
}
|
|
||||||
nodeBuilder := c.getNodeBuilder()
|
|
||||||
typeNode := nodeBuilder.TypeToTypeNode(t, enclosingDeclaration, combinedFlags, nodebuilder.InternalFlagsNone, nil)
|
|
||||||
if typeNode == nil {
|
|
||||||
panic("should always get typenode")
|
|
||||||
}
|
|
||||||
// The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`.
|
|
||||||
// Otherwise, we always strip comments out.
|
|
||||||
var printer *printer.Printer
|
|
||||||
if t == c.unresolvedType {
|
|
||||||
printer = createPrinterWithDefaults(nodeBuilder.EmitContext())
|
|
||||||
} else {
|
|
||||||
printer = createPrinterWithRemoveComments(nodeBuilder.EmitContext())
|
|
||||||
}
|
|
||||||
var sourceFile *ast.SourceFile
|
|
||||||
if enclosingDeclaration != nil {
|
|
||||||
sourceFile = ast.GetSourceFileOfNode(enclosingDeclaration)
|
|
||||||
}
|
|
||||||
printer.Write(typeNode /*sourceFile*/, sourceFile, writer, nil)
|
|
||||||
result := writer.String()
|
|
||||||
|
|
||||||
maxLength := defaultMaximumTruncationLength * 2
|
|
||||||
if noTruncation {
|
|
||||||
maxLength = noTruncationMaximumTruncationLength * 2
|
|
||||||
}
|
|
||||||
if maxLength > 0 && result != "" && len(result) >= maxLength {
|
|
||||||
return result[0:maxLength-len("...")] + "..."
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) SymbolToString(s *ast.Symbol) string {
|
|
||||||
return c.symbolToString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) symbolToString(symbol *ast.Symbol) string {
|
|
||||||
return c.symbolToStringEx(symbol, nil, ast.SymbolFlagsAll, SymbolFormatFlagsAllowAnyNodeKind)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) SymbolToStringEx(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags, flags SymbolFormatFlags) string {
|
|
||||||
return c.symbolToStringEx(symbol, enclosingDeclaration, meaning, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) symbolToStringEx(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags, flags SymbolFormatFlags) string {
|
|
||||||
writer, putWriter := printer.GetSingleLineStringWriter()
|
|
||||||
defer putWriter()
|
|
||||||
|
|
||||||
nodeFlags := nodebuilder.FlagsIgnoreErrors
|
|
||||||
internalNodeFlags := nodebuilder.InternalFlagsNone
|
|
||||||
if flags&SymbolFormatFlagsUseOnlyExternalAliasing != 0 {
|
|
||||||
nodeFlags |= nodebuilder.FlagsUseOnlyExternalAliasing
|
|
||||||
}
|
|
||||||
if flags&SymbolFormatFlagsWriteTypeParametersOrArguments != 0 {
|
|
||||||
nodeFlags |= nodebuilder.FlagsWriteTypeParametersInQualifiedName
|
|
||||||
}
|
|
||||||
if flags&SymbolFormatFlagsUseAliasDefinedOutsideCurrentScope != 0 {
|
|
||||||
nodeFlags |= nodebuilder.FlagsUseAliasDefinedOutsideCurrentScope
|
|
||||||
}
|
|
||||||
if flags&SymbolFormatFlagsDoNotIncludeSymbolChain != 0 {
|
|
||||||
internalNodeFlags |= nodebuilder.InternalFlagsDoNotIncludeSymbolChain
|
|
||||||
}
|
|
||||||
if flags&SymbolFormatFlagsWriteComputedProps != 0 {
|
|
||||||
internalNodeFlags |= nodebuilder.InternalFlagsWriteComputedProps
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeBuilder := c.getNodeBuilder()
|
|
||||||
var sourceFile *ast.SourceFile
|
|
||||||
if enclosingDeclaration != nil {
|
|
||||||
sourceFile = ast.GetSourceFileOfNode(enclosingDeclaration)
|
|
||||||
}
|
|
||||||
var printer_ *printer.Printer
|
|
||||||
// add neverAsciiEscape for GH#39027
|
|
||||||
if enclosingDeclaration != nil && enclosingDeclaration.Kind == ast.KindSourceFile {
|
|
||||||
printer_ = createPrinterWithRemoveCommentsNeverAsciiEscape(nodeBuilder.EmitContext())
|
|
||||||
} else {
|
|
||||||
printer_ = createPrinterWithRemoveComments(nodeBuilder.EmitContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder func(symbol *ast.Symbol, meaning ast.SymbolFlags, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node
|
|
||||||
if flags&SymbolFormatFlagsAllowAnyNodeKind != 0 {
|
|
||||||
builder = nodeBuilder.SymbolToNode
|
|
||||||
} else {
|
|
||||||
builder = nodeBuilder.SymbolToEntityName
|
|
||||||
}
|
|
||||||
entity := builder(symbol, meaning, enclosingDeclaration, nodeFlags, internalNodeFlags, nil) // TODO: GH#18217
|
|
||||||
printer_.Write(entity /*sourceFile*/, sourceFile, getTrailingSemicolonDeferringWriter(writer), nil) // TODO: GH#18217
|
|
||||||
return writer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) signatureToString(signature *Signature) string {
|
|
||||||
return c.signatureToStringEx(signature, nil, TypeFormatFlagsNone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) SignatureToStringEx(signature *Signature, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string {
|
|
||||||
return c.signatureToStringEx(signature, enclosingDeclaration, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) signatureToStringEx(signature *Signature, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string {
|
|
||||||
isConstructor := signature.flags&SignatureFlagsConstruct != 0 && flags&TypeFormatFlagsWriteCallStyleSignature == 0
|
|
||||||
var sigOutput ast.Kind
|
|
||||||
if flags&TypeFormatFlagsWriteArrowStyleSignature != 0 {
|
|
||||||
if isConstructor {
|
|
||||||
sigOutput = ast.KindConstructorType
|
|
||||||
} else {
|
|
||||||
sigOutput = ast.KindFunctionType
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if isConstructor {
|
|
||||||
sigOutput = ast.KindConstructSignature
|
|
||||||
} else {
|
|
||||||
sigOutput = ast.KindCallSignature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writer, putWriter := printer.GetSingleLineStringWriter()
|
|
||||||
defer putWriter()
|
|
||||||
|
|
||||||
nodeBuilder := c.getNodeBuilder()
|
|
||||||
combinedFlags := toNodeBuilderFlags(flags) | nodebuilder.FlagsIgnoreErrors | nodebuilder.FlagsWriteTypeParametersInQualifiedName
|
|
||||||
sig := nodeBuilder.SignatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, combinedFlags, nodebuilder.InternalFlagsNone, nil)
|
|
||||||
printer_ := createPrinterWithRemoveCommentsOmitTrailingSemicolon(nodeBuilder.EmitContext())
|
|
||||||
var sourceFile *ast.SourceFile
|
|
||||||
if enclosingDeclaration != nil {
|
|
||||||
sourceFile = ast.GetSourceFileOfNode(enclosingDeclaration)
|
|
||||||
}
|
|
||||||
printer_.Write(sig /*sourceFile*/, sourceFile, getTrailingSemicolonDeferringWriter(writer), nil) // TODO: GH#18217
|
|
||||||
return writer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) typePredicateToString(typePredicate *TypePredicate) string {
|
|
||||||
return c.typePredicateToStringEx(typePredicate, nil, TypeFormatFlagsUseAliasDefinedOutsideCurrentScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) typePredicateToStringEx(typePredicate *TypePredicate, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string {
|
|
||||||
writer, putWriter := printer.GetSingleLineStringWriter()
|
|
||||||
defer putWriter()
|
|
||||||
nodeBuilder := c.getNodeBuilder()
|
|
||||||
combinedFlags := toNodeBuilderFlags(flags) | nodebuilder.FlagsIgnoreErrors | nodebuilder.FlagsWriteTypeParametersInQualifiedName
|
|
||||||
predicate := nodeBuilder.TypePredicateToTypePredicateNode(typePredicate, enclosingDeclaration, combinedFlags, nodebuilder.InternalFlagsNone, nil) // TODO: GH#18217
|
|
||||||
printer_ := createPrinterWithRemoveComments(nodeBuilder.EmitContext())
|
|
||||||
var sourceFile *ast.SourceFile
|
|
||||||
if enclosingDeclaration != nil {
|
|
||||||
sourceFile = ast.GetSourceFileOfNode(enclosingDeclaration)
|
|
||||||
}
|
|
||||||
printer_.Write(predicate /*sourceFile*/, sourceFile, writer, nil)
|
|
||||||
return writer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) valueToString(value any) string {
|
|
||||||
return ValueToString(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) formatUnionTypes(types []*Type) []*Type {
|
|
||||||
var result []*Type
|
|
||||||
var flags TypeFlags
|
|
||||||
for i := 0; i < len(types); i++ {
|
|
||||||
t := types[i]
|
|
||||||
flags |= t.flags
|
|
||||||
if t.flags&TypeFlagsNullable == 0 {
|
|
||||||
if t.flags&(TypeFlagsBooleanLiteral|TypeFlagsEnumLike) != 0 {
|
|
||||||
var baseType *Type
|
|
||||||
if t.flags&TypeFlagsBooleanLiteral != 0 {
|
|
||||||
baseType = c.booleanType
|
|
||||||
} else {
|
|
||||||
baseType = c.getBaseTypeOfEnumLikeType(t)
|
|
||||||
}
|
|
||||||
if baseType.flags&TypeFlagsUnion != 0 {
|
|
||||||
count := len(baseType.AsUnionType().types)
|
|
||||||
if i+count <= len(types) && c.getRegularTypeOfLiteralType(types[i+count-1]) == c.getRegularTypeOfLiteralType(baseType.AsUnionType().types[count-1]) {
|
|
||||||
result = append(result, baseType)
|
|
||||||
i += count - 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = append(result, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if flags&TypeFlagsNull != 0 {
|
|
||||||
result = append(result, c.nullType)
|
|
||||||
}
|
|
||||||
if flags&TypeFlagsUndefined != 0 {
|
|
||||||
result = append(result, c.undefinedType)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TypeToTypeNode(t *Type, enclosingDeclaration *ast.Node, flags nodebuilder.Flags) *ast.TypeNode {
|
|
||||||
nodeBuilder := c.getNodeBuilder()
|
|
||||||
return nodeBuilder.TypeToTypeNode(t, enclosingDeclaration, flags, nodebuilder.InternalFlagsNone, nil)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,811 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"maps"
|
|
||||||
"slices"
|
|
||||||
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Checker) GetSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol {
|
|
||||||
return c.getSymbolsInScope(location, meaning)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol {
|
|
||||||
if location.Flags&ast.NodeFlagsInWithStatement != 0 {
|
|
||||||
// We cannot answer semantic questions within a with block, do not proceed any further
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
symbols := make(ast.SymbolTable)
|
|
||||||
isStaticSymbol := false
|
|
||||||
|
|
||||||
// Copy the given symbol into symbol tables if the symbol has the given meaning
|
|
||||||
// and it doesn't already exists in the symbol table.
|
|
||||||
copySymbol := func(symbol *ast.Symbol, meaning ast.SymbolFlags) {
|
|
||||||
if GetCombinedLocalAndExportSymbolFlags(symbol)&meaning != 0 {
|
|
||||||
id := symbol.Name
|
|
||||||
// We will copy all symbol regardless of its reserved name because
|
|
||||||
// symbolsToArray will check whether the key is a reserved name and
|
|
||||||
// it will not copy symbol with reserved name to the array
|
|
||||||
if _, ok := symbols[id]; !ok {
|
|
||||||
symbols[id] = symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
copySymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) {
|
|
||||||
if meaning != 0 {
|
|
||||||
for _, symbol := range source {
|
|
||||||
copySymbol(symbol, meaning)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
copyLocallyVisibleExportSymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) {
|
|
||||||
if meaning != 0 {
|
|
||||||
for _, symbol := range source {
|
|
||||||
// Similar condition as in `resolveNameHelper`
|
|
||||||
if ast.GetDeclarationOfKind(symbol, ast.KindExportSpecifier) == nil &&
|
|
||||||
ast.GetDeclarationOfKind(symbol, ast.KindNamespaceExport) == nil &&
|
|
||||||
symbol.Name != ast.InternalSymbolNameDefault {
|
|
||||||
copySymbol(symbol, meaning)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
populateSymbols := func() {
|
|
||||||
for location != nil {
|
|
||||||
if canHaveLocals(location) && location.Locals() != nil && !ast.IsGlobalSourceFile(location) {
|
|
||||||
copySymbols(location.Locals(), meaning)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch location.Kind {
|
|
||||||
case ast.KindSourceFile:
|
|
||||||
if !ast.IsExternalModule(location.AsSourceFile()) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case ast.KindModuleDeclaration:
|
|
||||||
copyLocallyVisibleExportSymbols(c.getSymbolOfDeclaration(location).Exports, meaning&ast.SymbolFlagsModuleMember)
|
|
||||||
case ast.KindEnumDeclaration:
|
|
||||||
copySymbols(c.getSymbolOfDeclaration(location).Exports, meaning&ast.SymbolFlagsEnumMember)
|
|
||||||
case ast.KindClassExpression:
|
|
||||||
className := location.AsClassExpression().Name()
|
|
||||||
if className != nil {
|
|
||||||
copySymbol(location.Symbol(), meaning)
|
|
||||||
}
|
|
||||||
// this fall-through is necessary because we would like to handle
|
|
||||||
// type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration.
|
|
||||||
fallthrough
|
|
||||||
case ast.KindClassDeclaration, ast.KindInterfaceDeclaration:
|
|
||||||
// If we didn't come from static member of class or interface,
|
|
||||||
// add the type parameters into the symbol table
|
|
||||||
// (type parameters of classDeclaration/classExpression and interface are in member property of the symbol.
|
|
||||||
// Note: that the memberFlags come from previous iteration.
|
|
||||||
if !isStaticSymbol {
|
|
||||||
copySymbols(c.getMembersOfSymbol(c.getSymbolOfDeclaration(location)), meaning&ast.SymbolFlagsType)
|
|
||||||
}
|
|
||||||
case ast.KindFunctionExpression:
|
|
||||||
funcName := location.Name()
|
|
||||||
if funcName != nil {
|
|
||||||
copySymbol(location.Symbol(), meaning)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if introducesArgumentsExoticObject(location) {
|
|
||||||
copySymbol(c.argumentsSymbol, meaning)
|
|
||||||
}
|
|
||||||
|
|
||||||
isStaticSymbol = ast.IsStatic(location)
|
|
||||||
location = location.Parent
|
|
||||||
}
|
|
||||||
|
|
||||||
copySymbols(c.globals, meaning)
|
|
||||||
}
|
|
||||||
|
|
||||||
populateSymbols()
|
|
||||||
|
|
||||||
delete(symbols, ast.InternalSymbolNameThis) // Not a symbol, a keyword
|
|
||||||
return symbolsToArray(symbols)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetExportsOfModule(symbol *ast.Symbol) []*ast.Symbol {
|
|
||||||
return symbolsToArray(c.getExportsOfModule(symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) ForEachExportAndPropertyOfModule(moduleSymbol *ast.Symbol, cb func(*ast.Symbol, string)) {
|
|
||||||
for key, exportedSymbol := range c.getExportsOfModule(moduleSymbol) {
|
|
||||||
if !isReservedMemberName(key) {
|
|
||||||
cb(exportedSymbol, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exportEquals := c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/)
|
|
||||||
if exportEquals == moduleSymbol {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
typeOfSymbol := c.getTypeOfSymbol(exportEquals)
|
|
||||||
if !c.shouldTreatPropertiesOfExternalModuleAsExports(typeOfSymbol) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// forEachPropertyOfType
|
|
||||||
reducedType := c.getReducedApparentType(typeOfSymbol)
|
|
||||||
if reducedType.flags&TypeFlagsStructuredType == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for name, symbol := range c.resolveStructuredTypeMembers(reducedType).members {
|
|
||||||
if c.isNamedMember(symbol, name) {
|
|
||||||
cb(symbol, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsValidPropertyAccess(node *ast.Node, propertyName string) bool {
|
|
||||||
return c.isValidPropertyAccess(node, propertyName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) isValidPropertyAccess(node *ast.Node, propertyName string) bool {
|
|
||||||
switch node.Kind {
|
|
||||||
case ast.KindPropertyAccessExpression:
|
|
||||||
return c.isValidPropertyAccessWithType(node, node.Expression().Kind == ast.KindSuperKeyword, propertyName, c.getWidenedType(c.checkExpression(node.Expression())))
|
|
||||||
case ast.KindQualifiedName:
|
|
||||||
return c.isValidPropertyAccessWithType(node, false /*isSuper*/, propertyName, c.getWidenedType(c.checkExpression(node.AsQualifiedName().Left)))
|
|
||||||
case ast.KindImportType:
|
|
||||||
return c.isValidPropertyAccessWithType(node, false /*isSuper*/, propertyName, c.getTypeFromTypeNode(node))
|
|
||||||
}
|
|
||||||
panic("Unexpected node kind in isValidPropertyAccess: " + node.Kind.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) isValidPropertyAccessWithType(node *ast.Node, isSuper bool, propertyName string, t *Type) bool {
|
|
||||||
// Short-circuiting for improved performance.
|
|
||||||
if IsTypeAny(t) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
prop := c.getPropertyOfType(t, propertyName)
|
|
||||||
return prop != nil && c.isPropertyAccessible(node, isSuper, false /*isWrite*/, t, prop)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if an existing property access is valid for completions purposes.
|
|
||||||
// node: a property access-like node where we want to check if we can access a property.
|
|
||||||
// This node does not need to be an access of the property we are checking.
|
|
||||||
// e.g. in completions, this node will often be an incomplete property access node, as in `foo.`.
|
|
||||||
// Besides providing a location (i.e. scope) used to check property accessibility, we use this node for
|
|
||||||
// computing whether this is a `super` property access.
|
|
||||||
// type: the type whose property we are checking.
|
|
||||||
// property: the accessed property's symbol.
|
|
||||||
func (c *Checker) IsValidPropertyAccessForCompletions(node *ast.Node, t *Type, property *ast.Symbol) bool {
|
|
||||||
return c.isPropertyAccessible(
|
|
||||||
node,
|
|
||||||
node.Kind == ast.KindPropertyAccessExpression && node.Expression().Kind == ast.KindSuperKeyword,
|
|
||||||
false, /*isWrite*/
|
|
||||||
t,
|
|
||||||
property,
|
|
||||||
)
|
|
||||||
// Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetAllPossiblePropertiesOfTypes(types []*Type) []*ast.Symbol {
|
|
||||||
unionType := c.getUnionType(types)
|
|
||||||
if unionType.flags&TypeFlagsUnion == 0 {
|
|
||||||
return c.getAugmentedPropertiesOfType(unionType)
|
|
||||||
}
|
|
||||||
|
|
||||||
props := make(ast.SymbolTable)
|
|
||||||
for _, memberType := range types {
|
|
||||||
augmentedProps := c.getAugmentedPropertiesOfType(memberType)
|
|
||||||
for _, p := range augmentedProps {
|
|
||||||
if _, ok := props[p.Name]; !ok {
|
|
||||||
prop := c.createUnionOrIntersectionProperty(unionType, p.Name, false /*skipObjectFunctionPropertyAugment*/)
|
|
||||||
// May be undefined if the property is private
|
|
||||||
if prop != nil {
|
|
||||||
props[p.Name] = prop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slices.Collect(maps.Values(props))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsUnknownSymbol(symbol *ast.Symbol) bool {
|
|
||||||
return symbol == c.unknownSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsUndefinedSymbol(symbol *ast.Symbol) bool {
|
|
||||||
return symbol == c.undefinedSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsArgumentsSymbol(symbol *ast.Symbol) bool {
|
|
||||||
return symbol == c.argumentsSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
// Originally from services.ts
|
|
||||||
func (c *Checker) GetNonOptionalType(t *Type) *Type {
|
|
||||||
return c.removeOptionalTypeMarker(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetStringIndexType(t *Type) *Type {
|
|
||||||
return c.getIndexTypeOfType(t, c.stringType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetNumberIndexType(t *Type) *Type {
|
|
||||||
return c.getIndexTypeOfType(t, c.numberType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetCallSignatures(t *Type) []*Signature {
|
|
||||||
return c.getSignaturesOfType(t, SignatureKindCall)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetConstructSignatures(t *Type) []*Signature {
|
|
||||||
return c.getSignaturesOfType(t, SignatureKindConstruct)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetApparentProperties(t *Type) []*ast.Symbol {
|
|
||||||
return c.getAugmentedPropertiesOfType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getAugmentedPropertiesOfType(t *Type) []*ast.Symbol {
|
|
||||||
t = c.getApparentType(t)
|
|
||||||
propsByName := createSymbolTable(c.getPropertiesOfType(t))
|
|
||||||
var functionType *Type
|
|
||||||
if len(c.getSignaturesOfType(t, SignatureKindCall)) > 0 {
|
|
||||||
functionType = c.globalCallableFunctionType
|
|
||||||
} else if len(c.getSignaturesOfType(t, SignatureKindConstruct)) > 0 {
|
|
||||||
functionType = c.globalNewableFunctionType
|
|
||||||
}
|
|
||||||
|
|
||||||
if propsByName == nil {
|
|
||||||
propsByName = make(ast.SymbolTable)
|
|
||||||
}
|
|
||||||
if functionType != nil {
|
|
||||||
for _, p := range c.getPropertiesOfType(functionType) {
|
|
||||||
if _, ok := propsByName[p.Name]; !ok {
|
|
||||||
propsByName[p.Name] = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.getNamedMembers(propsByName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TryGetMemberInModuleExportsAndProperties(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol {
|
|
||||||
symbol := c.TryGetMemberInModuleExports(memberName, moduleSymbol)
|
|
||||||
if symbol != nil {
|
|
||||||
return symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
exportEquals := c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/)
|
|
||||||
if exportEquals == moduleSymbol {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t := c.getTypeOfSymbol(exportEquals)
|
|
||||||
if c.shouldTreatPropertiesOfExternalModuleAsExports(t) {
|
|
||||||
return c.getPropertyOfType(t, memberName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) TryGetMemberInModuleExports(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol {
|
|
||||||
symbolTable := c.getExportsOfModule(moduleSymbol)
|
|
||||||
return symbolTable[memberName]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType *Type) bool {
|
|
||||||
return resolvedExternalModuleType.flags&TypeFlagsPrimitive == 0 ||
|
|
||||||
resolvedExternalModuleType.objectFlags&ObjectFlagsClass != 0 ||
|
|
||||||
// `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path.
|
|
||||||
c.isArrayType(resolvedExternalModuleType) ||
|
|
||||||
isTupleType(resolvedExternalModuleType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetContextualType(node *ast.Expression, contextFlags ContextFlags) *Type {
|
|
||||||
if contextFlags&ContextFlagsCompletions != 0 {
|
|
||||||
return runWithInferenceBlockedFromSourceNode(c, node, func() *Type { return c.getContextualType(node, contextFlags) })
|
|
||||||
}
|
|
||||||
return c.getContextualType(node, contextFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runWithInferenceBlockedFromSourceNode[T any](c *Checker, node *ast.Node, fn func() T) T {
|
|
||||||
containingCall := ast.FindAncestor(node, ast.IsCallLikeExpression)
|
|
||||||
if containingCall != nil {
|
|
||||||
toMarkSkip := node
|
|
||||||
for {
|
|
||||||
c.skipDirectInferenceNodes.Add(toMarkSkip)
|
|
||||||
toMarkSkip = toMarkSkip.Parent
|
|
||||||
if toMarkSkip == nil || toMarkSkip == containingCall {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.isInferencePartiallyBlocked = true
|
|
||||||
result := runWithoutResolvedSignatureCaching(c, node, fn)
|
|
||||||
c.isInferencePartiallyBlocked = false
|
|
||||||
|
|
||||||
c.skipDirectInferenceNodes.Clear()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetResolvedSignatureForSignatureHelp(node *ast.Node, argumentCount int, c *Checker) (*Signature, []*Signature) {
|
|
||||||
type result struct {
|
|
||||||
signature *Signature
|
|
||||||
candidates []*Signature
|
|
||||||
}
|
|
||||||
res := runWithoutResolvedSignatureCaching(c, node, func() result {
|
|
||||||
signature, candidates := c.getResolvedSignatureWorker(node, CheckModeIsForSignatureHelp, argumentCount)
|
|
||||||
return result{signature, candidates}
|
|
||||||
})
|
|
||||||
return res.signature, res.candidates
|
|
||||||
}
|
|
||||||
|
|
||||||
func runWithoutResolvedSignatureCaching[T any](c *Checker, node *ast.Node, fn func() T) T {
|
|
||||||
ancestorNode := ast.FindAncestor(node, ast.IsCallLikeOrFunctionLikeExpression)
|
|
||||||
if ancestorNode != nil {
|
|
||||||
cachedResolvedSignatures := make(map[*SignatureLinks]*Signature)
|
|
||||||
cachedTypes := make(map[*ValueSymbolLinks]*Type)
|
|
||||||
for ancestorNode != nil {
|
|
||||||
signatureLinks := c.signatureLinks.Get(ancestorNode)
|
|
||||||
cachedResolvedSignatures[signatureLinks] = signatureLinks.resolvedSignature
|
|
||||||
signatureLinks.resolvedSignature = nil
|
|
||||||
if ast.IsFunctionExpressionOrArrowFunction(ancestorNode) {
|
|
||||||
symbolLinks := c.valueSymbolLinks.Get(c.getSymbolOfDeclaration(ancestorNode))
|
|
||||||
resolvedType := symbolLinks.resolvedType
|
|
||||||
cachedTypes[symbolLinks] = resolvedType
|
|
||||||
symbolLinks.resolvedType = nil
|
|
||||||
}
|
|
||||||
ancestorNode = ast.FindAncestor(ancestorNode.Parent, ast.IsCallLikeOrFunctionLikeExpression)
|
|
||||||
}
|
|
||||||
result := fn()
|
|
||||||
for signatureLinks, resolvedSignature := range cachedResolvedSignatures {
|
|
||||||
signatureLinks.resolvedSignature = resolvedSignature
|
|
||||||
}
|
|
||||||
for symbolLinks, resolvedType := range cachedTypes {
|
|
||||||
symbolLinks.resolvedType = resolvedType
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
return fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) SkipAlias(symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
if symbol.Flags&ast.SymbolFlagsAlias != 0 {
|
|
||||||
return c.GetAliasedSymbol(symbol)
|
|
||||||
}
|
|
||||||
return symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetRootSymbols(symbol *ast.Symbol) []*ast.Symbol {
|
|
||||||
roots := c.getImmediateRootSymbols(symbol)
|
|
||||||
if len(roots) == 0 {
|
|
||||||
return []*ast.Symbol{symbol}
|
|
||||||
}
|
|
||||||
var result []*ast.Symbol
|
|
||||||
for _, root := range roots {
|
|
||||||
result = append(result, c.GetRootSymbols(root)...)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getImmediateRootSymbols(symbol *ast.Symbol) []*ast.Symbol {
|
|
||||||
if symbol.CheckFlags&ast.CheckFlagsSynthetic != 0 {
|
|
||||||
return core.MapNonNil(
|
|
||||||
c.valueSymbolLinks.Get(symbol).containingType.Types(),
|
|
||||||
func(t *Type) *ast.Symbol {
|
|
||||||
return c.getPropertyOfType(t, symbol.Name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if symbol.Flags&ast.SymbolFlagsTransient != 0 {
|
|
||||||
if c.spreadLinks.Has(symbol) {
|
|
||||||
leftSpread := c.spreadLinks.Get(symbol).leftSpread
|
|
||||||
rightSpread := c.spreadLinks.Get(symbol).rightSpread
|
|
||||||
if leftSpread != nil {
|
|
||||||
return []*ast.Symbol{leftSpread, rightSpread}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.mappedSymbolLinks.Has(symbol) {
|
|
||||||
syntheticOrigin := c.mappedSymbolLinks.Get(symbol).syntheticOrigin
|
|
||||||
if syntheticOrigin != nil {
|
|
||||||
return []*ast.Symbol{syntheticOrigin}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target := c.tryGetTarget(symbol)
|
|
||||||
if target != nil {
|
|
||||||
return []*ast.Symbol{target}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) tryGetTarget(symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
var target *ast.Symbol
|
|
||||||
next := symbol
|
|
||||||
for {
|
|
||||||
if c.valueSymbolLinks.Has(next) {
|
|
||||||
next = c.valueSymbolLinks.Get(next).target
|
|
||||||
} else if c.exportTypeLinks.Has(next) {
|
|
||||||
next = c.exportTypeLinks.Get(next).target
|
|
||||||
} else {
|
|
||||||
next = nil
|
|
||||||
}
|
|
||||||
if next == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
target = next
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetExportSymbolOfSymbol(symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
return c.getMergedSymbol(core.IfElse(symbol.ExportSymbol != nil, symbol.ExportSymbol, symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetExportSpecifierLocalTargetSymbol(node *ast.Node) *ast.Symbol {
|
|
||||||
// node should be ExportSpecifier | Identifier
|
|
||||||
switch node.Kind {
|
|
||||||
case ast.KindExportSpecifier:
|
|
||||||
if node.Parent.Parent.AsExportDeclaration().ModuleSpecifier != nil {
|
|
||||||
return c.getExternalModuleMember(node.Parent.Parent, node, false /*dontResolveAlias*/)
|
|
||||||
}
|
|
||||||
name := node.PropertyNameOrName()
|
|
||||||
if name.Kind == ast.KindStringLiteral {
|
|
||||||
// Skip for invalid syntax like this: export { "x" }
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.resolveEntityName(name, ast.SymbolFlagsValue|ast.SymbolFlagsType|ast.SymbolFlagsNamespace|ast.SymbolFlagsAlias, true /*ignoreErrors*/, false, nil)
|
|
||||||
case ast.KindIdentifier:
|
|
||||||
return c.resolveEntityName(node, ast.SymbolFlagsValue|ast.SymbolFlagsType|ast.SymbolFlagsNamespace|ast.SymbolFlagsAlias, true /*ignoreErrors*/, false, nil)
|
|
||||||
}
|
|
||||||
panic("Unhandled case in getExportSpecifierLocalTargetSymbol, node should be ExportSpecifier | Identifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetShorthandAssignmentValueSymbol(location *ast.Node) *ast.Symbol {
|
|
||||||
if location != nil && location.Kind == ast.KindShorthandPropertyAssignment {
|
|
||||||
return c.resolveEntityName(location.Name(), ast.SymbolFlagsValue|ast.SymbolFlagsAlias, true /*ignoreErrors*/, false, nil)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get symbols that represent parameter-property-declaration as parameter and as property declaration
|
|
||||||
* @param parameter a parameterDeclaration node
|
|
||||||
* @param parameterName a name of the parameter to get the symbols for.
|
|
||||||
* @return a tuple of two symbols
|
|
||||||
*/
|
|
||||||
func (c *Checker) GetSymbolsOfParameterPropertyDeclaration(parameter *ast.Node /*ParameterPropertyDeclaration*/, parameterName string) (*ast.Symbol, *ast.Symbol) {
|
|
||||||
constructorDeclaration := parameter.Parent
|
|
||||||
classDeclaration := parameter.Parent.Parent
|
|
||||||
|
|
||||||
parameterSymbol := c.getSymbol(constructorDeclaration.Locals(), parameterName, ast.SymbolFlagsValue)
|
|
||||||
propertySymbol := c.getSymbol(c.getMembersOfSymbol(classDeclaration.Symbol()), parameterName, ast.SymbolFlagsValue)
|
|
||||||
|
|
||||||
if parameterSymbol != nil && propertySymbol != nil {
|
|
||||||
return parameterSymbol, propertySymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("There should exist two symbols, one as property declaration and one as parameter declaration")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeArgumentConstraint(node *ast.Node) *Type {
|
|
||||||
if !ast.IsTypeNode(node) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.getTypeArgumentConstraint(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getTypeArgumentConstraint(node *ast.Node) *Type {
|
|
||||||
typeReferenceNode := core.IfElse(ast.IsTypeReferenceType(node.Parent), node.Parent, nil)
|
|
||||||
if typeReferenceNode == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
typeParameters := c.getTypeParametersForTypeReferenceOrImport(typeReferenceNode)
|
|
||||||
if len(typeParameters) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
typeParamIndex := core.FindIndex(typeReferenceNode.TypeArguments(), func(n *ast.Node) bool {
|
|
||||||
return n == node
|
|
||||||
})
|
|
||||||
constraint := c.getConstraintOfTypeParameter(typeParameters[typeParamIndex])
|
|
||||||
if constraint != nil {
|
|
||||||
return c.instantiateType(
|
|
||||||
constraint,
|
|
||||||
newTypeMapper(typeParameters, c.getEffectiveTypeArguments(typeReferenceNode, typeParameters)))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) IsTypeInvalidDueToUnionDiscriminant(contextualType *Type, obj *ast.Node) bool {
|
|
||||||
properties := obj.Properties()
|
|
||||||
return core.Some(properties, func(property *ast.Node) bool {
|
|
||||||
var nameType *Type
|
|
||||||
propertyName := property.Name()
|
|
||||||
if propertyName != nil {
|
|
||||||
if ast.IsJsxNamespacedName(propertyName) {
|
|
||||||
nameType = c.getStringLiteralType(propertyName.Text())
|
|
||||||
} else {
|
|
||||||
nameType = c.getLiteralTypeFromPropertyName(propertyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var name string
|
|
||||||
if nameType != nil && isTypeUsableAsPropertyName(nameType) {
|
|
||||||
name = getPropertyNameFromType(nameType)
|
|
||||||
}
|
|
||||||
var expected *Type
|
|
||||||
if name != "" {
|
|
||||||
expected = c.getTypeOfPropertyOfType(contextualType, name)
|
|
||||||
}
|
|
||||||
return expected != nil && isLiteralType(expected) && !c.isTypeAssignableTo(c.getTypeOfNode(property), expected)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlike `getExportsOfModule`, this includes properties of an `export =` value.
|
|
||||||
func (c *Checker) GetExportsAndPropertiesOfModule(moduleSymbol *ast.Symbol) []*ast.Symbol {
|
|
||||||
exports := c.getExportsOfModuleAsArray(moduleSymbol)
|
|
||||||
exportEquals := c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/)
|
|
||||||
if exportEquals != moduleSymbol {
|
|
||||||
t := c.getTypeOfSymbol(exportEquals)
|
|
||||||
if c.shouldTreatPropertiesOfExternalModuleAsExports(t) {
|
|
||||||
exports = append(exports, c.getPropertiesOfType(t)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exports
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getExportsOfModuleAsArray(moduleSymbol *ast.Symbol) []*ast.Symbol {
|
|
||||||
return symbolsToArray(c.getExportsOfModule(moduleSymbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns all the properties of the Jsx.IntrinsicElements interface.
|
|
||||||
func (c *Checker) GetJsxIntrinsicTagNamesAt(location *ast.Node) []*ast.Symbol {
|
|
||||||
intrinsics := c.getJsxType(JsxNames.IntrinsicElements, location)
|
|
||||||
if intrinsics == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.GetPropertiesOfType(intrinsics)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetContextualTypeForJsxAttribute(attribute *ast.JsxAttributeLike) *Type {
|
|
||||||
return c.getContextualTypeForJsxAttribute(attribute, ContextFlagsNone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetConstantValue(node *ast.Node) any {
|
|
||||||
if node.Kind == ast.KindEnumMember {
|
|
||||||
return c.getEnumMemberValue(node).Value
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.symbolNodeLinks.Get(node).resolvedSymbol == nil {
|
|
||||||
c.checkExpressionCached(node) // ensure cached resolved symbol is set
|
|
||||||
}
|
|
||||||
symbol := c.symbolNodeLinks.Get(node).resolvedSymbol
|
|
||||||
if symbol == nil && ast.IsEntityNameExpression(node) {
|
|
||||||
symbol = c.resolveEntityName(
|
|
||||||
node,
|
|
||||||
ast.SymbolFlagsValue,
|
|
||||||
true, /*ignoreErrors*/
|
|
||||||
false, /*dontResolveAlias*/
|
|
||||||
nil /*location*/)
|
|
||||||
}
|
|
||||||
if symbol != nil && symbol.Flags&ast.SymbolFlagsEnumMember != 0 {
|
|
||||||
// inline property\index accesses only for const enums
|
|
||||||
member := symbol.ValueDeclaration
|
|
||||||
if ast.IsEnumConst(member.Parent) {
|
|
||||||
return c.getEnumMemberValue(member).Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) getResolvedSignatureWorker(node *ast.Node, checkMode CheckMode, argumentCount int) (*Signature, []*Signature) {
|
|
||||||
parsedNode := printer.NewEmitContext().ParseNode(node)
|
|
||||||
c.apparentArgumentCount = &argumentCount
|
|
||||||
candidatesOutArray := &[]*Signature{}
|
|
||||||
var res *Signature
|
|
||||||
if parsedNode != nil {
|
|
||||||
res = c.getResolvedSignature(parsedNode, candidatesOutArray, checkMode)
|
|
||||||
}
|
|
||||||
c.apparentArgumentCount = nil
|
|
||||||
return res, *candidatesOutArray
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetCandidateSignaturesForStringLiteralCompletions(call *ast.CallLikeExpression, editingArgument *ast.Node) []*Signature {
|
|
||||||
// first, get candidates when inference is blocked from the source node.
|
|
||||||
candidates := runWithInferenceBlockedFromSourceNode(c, editingArgument, func() []*Signature {
|
|
||||||
_, blockedInferenceCandidates := c.getResolvedSignatureWorker(call, CheckModeNormal, 0)
|
|
||||||
return blockedInferenceCandidates
|
|
||||||
})
|
|
||||||
candidatesSet := collections.NewSetFromItems(candidates...)
|
|
||||||
|
|
||||||
// next, get candidates where the source node is considered for inference.
|
|
||||||
otherCandidates := runWithoutResolvedSignatureCaching(c, editingArgument, func() []*Signature {
|
|
||||||
_, inferenceCandidates := c.getResolvedSignatureWorker(call, CheckModeNormal, 0)
|
|
||||||
return inferenceCandidates
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, candidate := range otherCandidates {
|
|
||||||
if candidatesSet.Has(candidate) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
candidates = append(candidates, candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
return candidates
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetTypeParameterAtPosition(s *Signature, pos int) *Type {
|
|
||||||
t := c.getTypeAtPosition(s, pos)
|
|
||||||
if t.IsIndex() && isThisTypeParameter(t.AsIndexType().target) {
|
|
||||||
constraint := c.getBaseConstraintOfType(t.AsIndexType().target)
|
|
||||||
if constraint != nil {
|
|
||||||
return c.getIndexType(constraint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetContextualDeclarationsForObjectLiteralElement(objectLiteral *ast.Node, name string) []*ast.Node {
|
|
||||||
var result []*ast.Node
|
|
||||||
if t := c.getApparentTypeOfContextualType(objectLiteral, ContextFlagsNone); t != nil {
|
|
||||||
for _, t := range t.Distributed() {
|
|
||||||
prop := c.getPropertyOfType(t, name)
|
|
||||||
if prop != nil {
|
|
||||||
for _, declaration := range prop.Declarations {
|
|
||||||
result = core.AppendIfUnique(result, declaration)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, info := range c.getApplicableIndexInfos(t, c.getStringLiteralType(name)) {
|
|
||||||
if info.declaration != nil {
|
|
||||||
result = core.AppendIfUnique(result, info.declaration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
var knownGenericTypeNames = map[string]struct{}{
|
|
||||||
"Array": {},
|
|
||||||
"ArrayLike": {},
|
|
||||||
"ReadonlyArray": {},
|
|
||||||
"Promise": {},
|
|
||||||
"PromiseLike": {},
|
|
||||||
"Iterable": {},
|
|
||||||
"IterableIterator": {},
|
|
||||||
"AsyncIterable": {},
|
|
||||||
"Set": {},
|
|
||||||
"WeakSet": {},
|
|
||||||
"ReadonlySet": {},
|
|
||||||
"Map": {},
|
|
||||||
"WeakMap": {},
|
|
||||||
"ReadonlyMap": {},
|
|
||||||
"Partial": {},
|
|
||||||
"Required": {},
|
|
||||||
"Readonly": {},
|
|
||||||
"Pick": {},
|
|
||||||
"Omit": {},
|
|
||||||
"NonNullable": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
func isKnownGenericTypeName(name string) bool {
|
|
||||||
_, exists := knownGenericTypeNames[name]
|
|
||||||
return exists
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) GetFirstTypeArgumentFromKnownType(t *Type) *Type {
|
|
||||||
if t.objectFlags&ObjectFlagsReference != 0 && isKnownGenericTypeName(t.symbol.Name) {
|
|
||||||
symbol := c.getGlobalSymbol(t.symbol.Name, ast.SymbolFlagsType, nil)
|
|
||||||
if symbol != nil && symbol == t.Target().symbol {
|
|
||||||
return core.FirstOrNil(c.getTypeArguments(t))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t.alias != nil && isKnownGenericTypeName(t.alias.symbol.Name) {
|
|
||||||
symbol := c.getGlobalSymbol(t.alias.symbol.Name, ast.SymbolFlagsType, nil)
|
|
||||||
if symbol != nil && symbol == t.alias.symbol {
|
|
||||||
return core.FirstOrNil(t.alias.typeArguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets all symbols for one property. Does not get symbols for every property.
|
|
||||||
func (c *Checker) GetPropertySymbolsFromContextualType(node *ast.Node, contextualType *Type, unionSymbolOk bool) []*ast.Symbol {
|
|
||||||
name := ast.GetTextOfPropertyName(node.Name())
|
|
||||||
if name == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if contextualType.flags&TypeFlagsUnion == 0 {
|
|
||||||
if symbol := c.getPropertyOfType(contextualType, name); symbol != nil {
|
|
||||||
return []*ast.Symbol{symbol}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
filteredTypes := contextualType.Types()
|
|
||||||
if ast.IsObjectLiteralExpression(node.Parent) || ast.IsJsxAttributes(node.Parent) {
|
|
||||||
filteredTypes = core.Filter(filteredTypes, func(t *Type) bool {
|
|
||||||
return !c.IsTypeInvalidDueToUnionDiscriminant(t, node.Parent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
discriminatedPropertySymbols := core.MapNonNil(filteredTypes, func(t *Type) *ast.Symbol {
|
|
||||||
return c.getPropertyOfType(t, name)
|
|
||||||
})
|
|
||||||
if unionSymbolOk && (len(discriminatedPropertySymbols) == 0 || len(discriminatedPropertySymbols) == len(contextualType.Types())) {
|
|
||||||
if symbol := c.getPropertyOfType(contextualType, name); symbol != nil {
|
|
||||||
return []*ast.Symbol{symbol}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(filteredTypes) == 0 && len(discriminatedPropertySymbols) == 0 {
|
|
||||||
// Bad discriminant -- do again without discriminating
|
|
||||||
return core.MapNonNil(contextualType.Types(), func(t *Type) *ast.Symbol {
|
|
||||||
return c.getPropertyOfType(t, name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// by eliminating duplicates we might even end up with a single symbol
|
|
||||||
// that helps with displaying better quick infos on properties of union types
|
|
||||||
return core.Deduplicate(discriminatedPropertySymbols)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the property symbol corresponding to the property in destructuring assignment
|
|
||||||
// 'property1' from
|
|
||||||
//
|
|
||||||
// for ( { property1: a } of elems) {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// 'property1' at location 'a' from:
|
|
||||||
//
|
|
||||||
// [a] = [ property1, property2 ]
|
|
||||||
func (c *Checker) GetPropertySymbolOfDestructuringAssignment(location *ast.Node) *ast.Symbol {
|
|
||||||
if ast.IsArrayLiteralOrObjectLiteralDestructuringPattern(location.Parent.Parent) {
|
|
||||||
// Get the type of the object or array literal and then look for property of given name in the type
|
|
||||||
if typeOfObjectLiteral := c.getTypeOfAssignmentPattern(location.Parent.Parent); typeOfObjectLiteral != nil {
|
|
||||||
return c.getPropertyOfType(typeOfObjectLiteral, location.Text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the type of object literal or array literal of destructuring assignment.
|
|
||||||
// { a } from
|
|
||||||
//
|
|
||||||
// for ( { a } of elems) {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [ a ] from
|
|
||||||
//
|
|
||||||
// [a] = [ some array ...]
|
|
||||||
func (c *Checker) getTypeOfAssignmentPattern(expr *ast.Node) *Type {
|
|
||||||
// If this is from "for of"
|
|
||||||
// for ( { a } of elems) {
|
|
||||||
// }
|
|
||||||
if ast.IsForOfStatement(expr.Parent) {
|
|
||||||
iteratedType := c.checkRightHandSideOfForOf(expr.Parent)
|
|
||||||
return c.checkDestructuringAssignment(expr, core.OrElse(iteratedType, c.errorType), CheckModeNormal, false)
|
|
||||||
}
|
|
||||||
// If this is from "for" initializer
|
|
||||||
// for ({a } = elems[0];.....) { }
|
|
||||||
if ast.IsBinaryExpression(expr.Parent) {
|
|
||||||
iteratedType := c.getTypeOfExpression(expr.Parent.AsBinaryExpression().Right)
|
|
||||||
return c.checkDestructuringAssignment(expr, core.OrElse(iteratedType, c.errorType), CheckModeNormal, false)
|
|
||||||
}
|
|
||||||
// If this is from nested object binding pattern
|
|
||||||
// for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) {
|
|
||||||
if ast.IsPropertyAssignment(expr.Parent) {
|
|
||||||
node := expr.Parent.Parent
|
|
||||||
typeOfParentObjectLiteral := core.OrElse(c.getTypeOfAssignmentPattern(node), c.errorType)
|
|
||||||
propertyIndex := slices.Index(node.AsObjectLiteralExpression().Properties.Nodes, expr.Parent)
|
|
||||||
return c.checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral, propertyIndex, nil, false)
|
|
||||||
}
|
|
||||||
// Array literal assignment - array destructuring pattern
|
|
||||||
node := expr.Parent
|
|
||||||
// [{ property1: p1, property2 }] = elems;
|
|
||||||
typeOfArrayLiteral := core.OrElse(c.getTypeOfAssignmentPattern(node), c.errorType)
|
|
||||||
elementType := core.OrElse(c.checkIteratedTypeOrElementType(IterationUseDestructuring, typeOfArrayLiteral, c.undefinedType, expr.Parent), c.errorType)
|
|
||||||
return c.checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, slices.Index(node.AsArrayLiteralExpression().Elements.Nodes, expr), elementType, CheckModeNormal)
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
// Code generated by "stringer -type=SignatureKind -output=stringer_generated.go"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package checker
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
|
||||||
// Re-run the stringer command to generate them again.
|
|
||||||
var x [1]struct{}
|
|
||||||
_ = x[SignatureKindCall-0]
|
|
||||||
_ = x[SignatureKindConstruct-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _SignatureKind_name = "SignatureKindCallSignatureKindConstruct"
|
|
||||||
|
|
||||||
var _SignatureKind_index = [...]uint8{0, 17, 39}
|
|
||||||
|
|
||||||
func (i SignatureKind) String() string {
|
|
||||||
if i < 0 || i >= SignatureKind(len(_SignatureKind_index)-1) {
|
|
||||||
return "SignatureKind(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
return _SignatureKind_name[_SignatureKind_index[i]:_SignatureKind_index[i+1]]
|
|
||||||
}
|
|
||||||
@ -1,759 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"slices"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (ch *Checker) IsTypeSymbolAccessible(typeSymbol *ast.Symbol, enclosingDeclaration *ast.Node) bool {
|
|
||||||
access := ch.isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, ast.SymbolFlagsType /*shouldComputeAliasesToMakeVisible*/, false /*allowModules*/, true)
|
|
||||||
return access.Accessibility == printer.SymbolAccessibilityAccessible
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) IsValueSymbolAccessible(symbol *ast.Symbol, enclosingDeclaration *ast.Node) bool {
|
|
||||||
access := ch.isSymbolAccessibleWorker(symbol, enclosingDeclaration, ast.SymbolFlagsValue /*shouldComputeAliasesToMakeVisible*/, false /*allowModules*/, true)
|
|
||||||
return access.Accessibility == printer.SymbolAccessibilityAccessible
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) IsSymbolAccessibleByFlags(symbol *ast.Symbol, enclosingDeclaration *ast.Node, flags ast.SymbolFlags) bool {
|
|
||||||
access := ch.isSymbolAccessibleWorker(symbol, enclosingDeclaration, flags /*shouldComputeAliasesToMakeVisible*/, false /*allowModules*/, false) // TODO: Strada bug? Why is this allowModules: false?
|
|
||||||
return access.Accessibility == printer.SymbolAccessibilityAccessible
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) IsAnySymbolAccessible(symbols []*ast.Symbol, enclosingDeclaration *ast.Node, initialSymbol *ast.Symbol, meaning ast.SymbolFlags, shouldComputeAliasesToMakeVisible bool, allowModules bool) *printer.SymbolAccessibilityResult {
|
|
||||||
if len(symbols) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var hadAccessibleChain *ast.Symbol
|
|
||||||
earlyModuleBail := false
|
|
||||||
for _, symbol := range symbols {
|
|
||||||
// Symbol is accessible if it by itself is accessible
|
|
||||||
accessibleSymbolChain := ch.getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning /*useOnlyExternalAliasing*/, false)
|
|
||||||
if len(accessibleSymbolChain) > 0 {
|
|
||||||
hadAccessibleChain = symbol
|
|
||||||
// TODO: going through emit resolver here is weird. Relayer these APIs.
|
|
||||||
hasAccessibleDeclarations := ch.GetEmitResolver().hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible)
|
|
||||||
if hasAccessibleDeclarations != nil {
|
|
||||||
return hasAccessibleDeclarations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if allowModules {
|
|
||||||
if core.Some(symbol.Declarations, hasNonGlobalAugmentationExternalModuleSymbol) {
|
|
||||||
if shouldComputeAliasesToMakeVisible {
|
|
||||||
earlyModuleBail = true
|
|
||||||
// Generally speaking, we want to use the aliases that already exist to refer to a module, if present
|
|
||||||
// In order to do so, we need to find those aliases in order to retain them in declaration emit; so
|
|
||||||
// if we are in declaration emit, we cannot use the fast path for module visibility until we've exhausted
|
|
||||||
// all other visibility options (in order to capture the possible aliases used to reference the module)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Any meaning of a module symbol is always accessible via an `import` type
|
|
||||||
return &printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityAccessible,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
|
|
||||||
// It could be a qualified symbol and hence verify the path
|
|
||||||
// e.g.:
|
|
||||||
// module m {
|
|
||||||
// export class c {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// const x: typeof m.c
|
|
||||||
// In the above example when we start with checking if typeof m.c symbol is accessible,
|
|
||||||
// we are going to see if c can be accessed in scope directly.
|
|
||||||
// But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
|
|
||||||
// It is accessible if the parent m is accessible because then m.c can be accessed through qualification
|
|
||||||
|
|
||||||
containers := ch.getContainersOfSymbol(symbol, enclosingDeclaration, meaning)
|
|
||||||
nextMeaning := meaning
|
|
||||||
if initialSymbol == symbol {
|
|
||||||
nextMeaning = getQualifiedLeftMeaning(meaning)
|
|
||||||
}
|
|
||||||
parentResult := ch.IsAnySymbolAccessible(containers, enclosingDeclaration, initialSymbol, nextMeaning, shouldComputeAliasesToMakeVisible, allowModules)
|
|
||||||
if parentResult != nil {
|
|
||||||
return parentResult
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if earlyModuleBail {
|
|
||||||
return &printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityAccessible,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hadAccessibleChain != nil {
|
|
||||||
var moduleName string
|
|
||||||
if hadAccessibleChain != initialSymbol {
|
|
||||||
moduleName = ch.symbolToStringEx(hadAccessibleChain, enclosingDeclaration, ast.SymbolFlagsNamespace, SymbolFormatFlagsAllowAnyNodeKind)
|
|
||||||
}
|
|
||||||
return &printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityNotAccessible,
|
|
||||||
ErrorSymbolName: ch.symbolToStringEx(initialSymbol, enclosingDeclaration, meaning, SymbolFormatFlagsAllowAnyNodeKind),
|
|
||||||
ErrorModuleName: moduleName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasNonGlobalAugmentationExternalModuleSymbol(declaration *ast.Node) bool {
|
|
||||||
return ast.IsModuleWithStringLiteralName(declaration) || (declaration.Kind == ast.KindSourceFile && ast.IsExternalOrCommonJSModule(declaration.AsSourceFile()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getQualifiedLeftMeaning(rightMeaning ast.SymbolFlags) ast.SymbolFlags {
|
|
||||||
// If we are looking in value space, the parent meaning is value, other wise it is namespace
|
|
||||||
if rightMeaning == ast.SymbolFlagsValue {
|
|
||||||
return ast.SymbolFlagsValue
|
|
||||||
}
|
|
||||||
return ast.SymbolFlagsNamespace
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol {
|
|
||||||
additionalContainers := core.MapNonNil(container.Declarations, func(d *ast.Node) *ast.Symbol {
|
|
||||||
return ch.getFileSymbolIfFileSymbolExportEqualsContainer(d, container)
|
|
||||||
})
|
|
||||||
var reexportContainers []*ast.Symbol
|
|
||||||
if enclosingDeclaration != nil {
|
|
||||||
reexportContainers = ch.getAlternativeContainingModules(symbol, enclosingDeclaration)
|
|
||||||
}
|
|
||||||
objectLiteralContainer := ch.getVariableDeclarationOfObjectLiteral(container, meaning)
|
|
||||||
leftMeaning := getQualifiedLeftMeaning(meaning)
|
|
||||||
if enclosingDeclaration != nil &&
|
|
||||||
container.Flags&leftMeaning != 0 &&
|
|
||||||
len(ch.getAccessibleSymbolChain(container, enclosingDeclaration, ast.SymbolFlagsNamespace /*useOnlyExternalAliasing*/, false)) > 0 {
|
|
||||||
// This order expresses a preference for the real container if it is in scope
|
|
||||||
res := append(append([]*ast.Symbol{container}, additionalContainers...), reexportContainers...)
|
|
||||||
if objectLiteralContainer != nil {
|
|
||||||
res = append(res, objectLiteralContainer)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
// we potentially have a symbol which is a member of the instance side of something - look for a variable in scope with the container's type
|
|
||||||
// which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`)
|
|
||||||
var firstVariableMatch *ast.Symbol
|
|
||||||
if (meaning == ast.SymbolFlagsValue &&
|
|
||||||
container.Flags&leftMeaning == 0) &&
|
|
||||||
container.Flags&ast.SymbolFlagsType != 0 &&
|
|
||||||
ch.getDeclaredTypeOfSymbol(container).flags&TypeFlagsObject != 0 {
|
|
||||||
ch.someSymbolTableInScope(enclosingDeclaration, func(t ast.SymbolTable, _ bool, _ bool, _ *ast.Node) bool {
|
|
||||||
for _, s := range t {
|
|
||||||
if s.Flags&leftMeaning != 0 && ch.getTypeOfSymbol(s) == ch.getDeclaredTypeOfSymbol(container) {
|
|
||||||
firstVariableMatch = s
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*ast.Symbol
|
|
||||||
if firstVariableMatch != nil {
|
|
||||||
res = append(res, firstVariableMatch)
|
|
||||||
}
|
|
||||||
res = append(res, additionalContainers...)
|
|
||||||
res = append(res, container)
|
|
||||||
if objectLiteralContainer != nil {
|
|
||||||
res = append(res, objectLiteralContainer)
|
|
||||||
}
|
|
||||||
res = append(res, reexportContainers...)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getAlternativeContainingModules(symbol *ast.Symbol, enclosingDeclaration *ast.Node) []*ast.Symbol {
|
|
||||||
if enclosingDeclaration == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
containingFile := ast.GetSourceFileOfNode(enclosingDeclaration)
|
|
||||||
id := ast.GetNodeId(containingFile.AsNode())
|
|
||||||
links := ch.symbolContainerLinks.Get(symbol)
|
|
||||||
if links.extendedContainersByFile == nil {
|
|
||||||
links.extendedContainersByFile = make(map[ast.NodeId][]*ast.Symbol)
|
|
||||||
}
|
|
||||||
existing, ok := links.extendedContainersByFile[id]
|
|
||||||
if ok && existing != nil {
|
|
||||||
return existing
|
|
||||||
}
|
|
||||||
var results []*ast.Symbol
|
|
||||||
if len(containingFile.Imports()) > 0 {
|
|
||||||
// Try to make an import using an import already in the enclosing file, if possible
|
|
||||||
for _, importRef := range containingFile.Imports() {
|
|
||||||
if ast.NodeIsSynthesized(importRef) {
|
|
||||||
// Synthetic names can't be resolved by `resolveExternalModuleName` - they'll cause a debug assert if they error
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resolvedModule := ch.resolveExternalModuleName(enclosingDeclaration, importRef /*ignoreErrors*/, true)
|
|
||||||
if resolvedModule == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ref := ch.getAliasForSymbolInContainer(resolvedModule, symbol)
|
|
||||||
if ref == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
results = append(results, resolvedModule)
|
|
||||||
}
|
|
||||||
if len(results) > 0 {
|
|
||||||
links.extendedContainersByFile[id] = results
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if links.extendedContainers != nil {
|
|
||||||
return *links.extendedContainers
|
|
||||||
}
|
|
||||||
// No results from files already being imported by this file - expand search (expensive, but not location-specific, so cached)
|
|
||||||
otherFiles := ch.program.SourceFiles()
|
|
||||||
for _, file := range otherFiles {
|
|
||||||
if !ast.IsExternalModule(file) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sym := ch.getSymbolOfDeclaration(file.AsNode())
|
|
||||||
ref := ch.getAliasForSymbolInContainer(sym, symbol)
|
|
||||||
if ref == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
results = append(results, sym)
|
|
||||||
}
|
|
||||||
links.extendedContainers = &results
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getVariableDeclarationOfObjectLiteral(symbol *ast.Symbol, meaning ast.SymbolFlags) *ast.Symbol {
|
|
||||||
// If we're trying to reference some object literal in, eg `var a = { x: 1 }`, the symbol for the literal, `__object`, is distinct
|
|
||||||
// from the symbol of the declaration it is being assigned to. Since we can use the declaration to refer to the literal, however,
|
|
||||||
// we'd like to make that connection here - potentially causing us to paint the declaration's visibility, and therefore the literal.
|
|
||||||
if meaning&ast.SymbolFlagsValue == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(symbol.Declarations) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
firstDecl := symbol.Declarations[0]
|
|
||||||
if firstDecl.Parent == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !ast.IsVariableDeclaration(firstDecl.Parent) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ast.IsObjectLiteralExpression(firstDecl) && firstDecl == firstDecl.Parent.Initializer() || ast.IsTypeLiteralNode(firstDecl) && firstDecl == firstDecl.Parent.Type() {
|
|
||||||
return ch.getSymbolOfDeclaration(firstDecl.Parent)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasExternalModuleSymbol(declaration *ast.Node) bool {
|
|
||||||
return ast.IsAmbientModule(declaration) || (declaration.Kind == ast.KindSourceFile && ast.IsExternalOrCommonJSModule(declaration.AsSourceFile()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getExternalModuleContainer(declaration *ast.Node) *ast.Symbol {
|
|
||||||
node := ast.FindAncestor(declaration, hasExternalModuleSymbol)
|
|
||||||
if node == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return ch.getSymbolOfDeclaration(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getFileSymbolIfFileSymbolExportEqualsContainer(d *ast.Node, container *ast.Symbol) *ast.Symbol {
|
|
||||||
fileSymbol := ch.getExternalModuleContainer(d)
|
|
||||||
if fileSymbol == nil || fileSymbol.Exports == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
exported, ok := fileSymbol.Exports[ast.InternalSymbolNameExportEquals]
|
|
||||||
if !ok || exported == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ch.getSymbolIfSameReference(exported, container) != nil {
|
|
||||||
return fileSymbol
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to find the symbol corresponding to the container a symbol is in - usually this
|
|
||||||
* is just its' `.parent`, but for locals, this value is `undefined`
|
|
||||||
*/
|
|
||||||
func (ch *Checker) getContainersOfSymbol(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol {
|
|
||||||
container := ch.getParentOfSymbol(symbol)
|
|
||||||
// Type parameters end up in the `members` lists but are not externally visible
|
|
||||||
if container != nil && (symbol.Flags&ast.SymbolFlagsTypeParameter == 0) {
|
|
||||||
return ch.getWithAlternativeContainers(container, symbol, enclosingDeclaration, meaning)
|
|
||||||
}
|
|
||||||
var candidates []*ast.Symbol
|
|
||||||
for _, d := range symbol.Declarations {
|
|
||||||
if !ast.IsAmbientModule(d) && d.Parent != nil {
|
|
||||||
// direct children of a module
|
|
||||||
if hasNonGlobalAugmentationExternalModuleSymbol(d.Parent) {
|
|
||||||
sym := ch.getSymbolOfDeclaration(d.Parent)
|
|
||||||
if sym != nil && !slices.Contains(candidates, sym) {
|
|
||||||
candidates = append(candidates, sym)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// export ='d member of an ambient module
|
|
||||||
if ast.IsModuleBlock(d.Parent) && d.Parent.Parent != nil && ch.resolveExternalModuleSymbol(ch.getSymbolOfDeclaration(d.Parent.Parent), false) == symbol {
|
|
||||||
sym := ch.getSymbolOfDeclaration(d.Parent.Parent)
|
|
||||||
if sym != nil && !slices.Contains(candidates, sym) {
|
|
||||||
candidates = append(candidates, sym)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ast.IsClassExpression(d) && ast.IsBinaryExpression(d.Parent) && d.Parent.AsBinaryExpression().OperatorToken.Kind == ast.KindEqualsToken && ast.IsAccessExpression(d.Parent.AsBinaryExpression().Left) && ast.IsEntityNameExpression(d.Parent.AsBinaryExpression().Left.Expression()) {
|
|
||||||
if ast.IsModuleExportsAccessExpression(d.Parent.AsBinaryExpression().Left) || ast.IsExportsIdentifier(d.Parent.AsBinaryExpression().Left.Expression()) {
|
|
||||||
sym := ch.getSymbolOfDeclaration(ast.GetSourceFileOfNode(d).AsNode())
|
|
||||||
if sym != nil && !slices.Contains(candidates, sym) {
|
|
||||||
candidates = append(candidates, sym)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ch.checkExpressionCached(d.Parent.AsBinaryExpression().Left.Expression())
|
|
||||||
sym := ch.symbolNodeLinks.Get(d.Parent.AsBinaryExpression().Left.Expression()).resolvedSymbol
|
|
||||||
if sym != nil && !slices.Contains(candidates, sym) {
|
|
||||||
candidates = append(candidates, sym)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(candidates) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var bestContainers []*ast.Symbol
|
|
||||||
var alternativeContainers []*ast.Symbol
|
|
||||||
for _, container := range candidates {
|
|
||||||
if ch.getAliasForSymbolInContainer(container, symbol) == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
allAlts := ch.getWithAlternativeContainers(container, symbol, enclosingDeclaration, meaning)
|
|
||||||
if len(allAlts) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bestContainers = append(bestContainers, allAlts[0])
|
|
||||||
alternativeContainers = append(alternativeContainers, allAlts[1:]...)
|
|
||||||
}
|
|
||||||
return append(bestContainers, alternativeContainers...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *ast.Symbol) *ast.Symbol {
|
|
||||||
if container == ch.getParentOfSymbol(symbol) {
|
|
||||||
// fast path, `symbol` is either already the alias or isn't aliased
|
|
||||||
return symbol
|
|
||||||
}
|
|
||||||
// Check if container is a thing with an `export=` which points directly at `symbol`, and if so, return
|
|
||||||
// the container itself as the alias for the symbol
|
|
||||||
if container.Exports != nil {
|
|
||||||
exportEquals, ok := container.Exports[ast.InternalSymbolNameExportEquals]
|
|
||||||
if ok && exportEquals != nil && ch.getSymbolIfSameReference(exportEquals, symbol) != nil {
|
|
||||||
return container
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports := ch.getExportsOfSymbol(container)
|
|
||||||
quick, ok := exports[symbol.Name]
|
|
||||||
if ok && quick != nil && ch.getSymbolIfSameReference(quick, symbol) != nil {
|
|
||||||
return quick
|
|
||||||
}
|
|
||||||
var candidates []*ast.Symbol
|
|
||||||
for _, exported := range exports {
|
|
||||||
if ch.getSymbolIfSameReference(exported, symbol) != nil {
|
|
||||||
candidates = append(candidates, exported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(candidates) > 0 {
|
|
||||||
ch.sortSymbols(candidates) // _must_ sort exports for stable results - symbol table is randomly iterated
|
|
||||||
return candidates[0]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getAccessibleSymbolChain(
|
|
||||||
symbol *ast.Symbol,
|
|
||||||
enclosingDeclaration *ast.Node,
|
|
||||||
meaning ast.SymbolFlags,
|
|
||||||
useOnlyExternalAliasing bool,
|
|
||||||
) []*ast.Symbol {
|
|
||||||
return ch.getAccessibleSymbolChainEx(accessibleSymbolChainContext{symbol, enclosingDeclaration, meaning, useOnlyExternalAliasing, make(map[ast.SymbolId]map[unsafe.Pointer]struct{})})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) GetAccessibleSymbolChain(
|
|
||||||
symbol *ast.Symbol,
|
|
||||||
enclosingDeclaration *ast.Node,
|
|
||||||
meaning ast.SymbolFlags,
|
|
||||||
useOnlyExternalAliasing bool,
|
|
||||||
) []*ast.Symbol {
|
|
||||||
return ch.getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, useOnlyExternalAliasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
type accessibleSymbolChainContext struct {
|
|
||||||
symbol *ast.Symbol
|
|
||||||
enclosingDeclaration *ast.Node
|
|
||||||
meaning ast.SymbolFlags
|
|
||||||
useOnlyExternalAliasing bool
|
|
||||||
visitedSymbolTablesMap map[ast.SymbolId]map[unsafe.Pointer]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getAccessibleSymbolChainEx(ctx accessibleSymbolChainContext) []*ast.Symbol {
|
|
||||||
if ctx.symbol == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if isPropertyOrMethodDeclarationSymbol(ctx.symbol) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more
|
|
||||||
var firstRelevantLocation *ast.Node
|
|
||||||
ch.someSymbolTableInScope(ctx.enclosingDeclaration, func(_ ast.SymbolTable, _ bool, _ bool, node *ast.Node) bool {
|
|
||||||
firstRelevantLocation = node
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
links := ch.symbolContainerLinks.Get(ctx.symbol)
|
|
||||||
linkKey := accessibleChainCacheKey{ctx.useOnlyExternalAliasing, firstRelevantLocation, ctx.meaning}
|
|
||||||
if links.accessibleChainCache == nil {
|
|
||||||
links.accessibleChainCache = make(map[accessibleChainCacheKey][]*ast.Symbol)
|
|
||||||
}
|
|
||||||
existing, ok := links.accessibleChainCache[linkKey]
|
|
||||||
if ok {
|
|
||||||
return existing
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []*ast.Symbol
|
|
||||||
|
|
||||||
ch.someSymbolTableInScope(ctx.enclosingDeclaration, func(t ast.SymbolTable, ignoreQualification bool, isLocalNameLookup bool, _ *ast.Node) bool {
|
|
||||||
res := ch.getAccessibleSymbolChainFromSymbolTable(ctx, t, ignoreQualification, isLocalNameLookup)
|
|
||||||
if len(res) > 0 {
|
|
||||||
result = res
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
links.accessibleChainCache[linkKey] = result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already)
|
|
||||||
*/
|
|
||||||
func (ch *Checker) getAccessibleSymbolChainFromSymbolTable(ctx accessibleSymbolChainContext, t ast.SymbolTable, ignoreQualification bool, isLocalNameLookup bool) []*ast.Symbol {
|
|
||||||
symId := ast.GetSymbolId(ctx.symbol)
|
|
||||||
visitedSymbolTables, ok := ctx.visitedSymbolTablesMap[symId]
|
|
||||||
if !ok {
|
|
||||||
visitedSymbolTables = make(map[unsafe.Pointer]struct{})
|
|
||||||
ctx.visitedSymbolTablesMap[symId] = visitedSymbolTables
|
|
||||||
}
|
|
||||||
|
|
||||||
id := reflect.ValueOf(t).UnsafePointer() // TODO: Is this seriously the only way to check reference equality of maps?
|
|
||||||
_, present := visitedSymbolTables[id]
|
|
||||||
if present {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
visitedSymbolTables[id] = struct{}{}
|
|
||||||
|
|
||||||
res := ch.trySymbolTable(ctx, t, ignoreQualification, isLocalNameLookup)
|
|
||||||
|
|
||||||
delete(visitedSymbolTables, id)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) trySymbolTable(
|
|
||||||
ctx accessibleSymbolChainContext,
|
|
||||||
symbols ast.SymbolTable,
|
|
||||||
ignoreQualification bool,
|
|
||||||
isLocalNameLookup bool,
|
|
||||||
) []*ast.Symbol {
|
|
||||||
// If symbol is directly available by its name in the symbol table
|
|
||||||
res, ok := symbols[ctx.symbol.Name]
|
|
||||||
if ok && res != nil && ch.isAccessible(ctx, res /*resolvedAliasSymbol*/, nil, ignoreQualification) {
|
|
||||||
return []*ast.Symbol{ctx.symbol}
|
|
||||||
}
|
|
||||||
|
|
||||||
var candidateChains [][]*ast.Symbol
|
|
||||||
// collect all possible chains to sort them and return the shortest/best
|
|
||||||
for _, symbolFromSymbolTable := range symbols {
|
|
||||||
// for every non-default, non-export= alias symbol in scope, check if it refers to or can chain to the target symbol
|
|
||||||
if symbolFromSymbolTable.Flags&ast.SymbolFlagsAlias != 0 &&
|
|
||||||
symbolFromSymbolTable.Name != ast.InternalSymbolNameExportEquals &&
|
|
||||||
symbolFromSymbolTable.Name != ast.InternalSymbolNameDefault &&
|
|
||||||
!(isUMDExportSymbol(symbolFromSymbolTable) && ctx.enclosingDeclaration != nil && ast.IsExternalModule(ast.GetSourceFileOfNode(ctx.enclosingDeclaration))) &&
|
|
||||||
// If `!useOnlyExternalAliasing`, we can use any type of alias to get the name
|
|
||||||
(!ctx.useOnlyExternalAliasing || core.Some(symbolFromSymbolTable.Declarations, ast.IsExternalModuleImportEqualsDeclaration)) &&
|
|
||||||
// If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it
|
|
||||||
(isLocalNameLookup && !core.Some(symbolFromSymbolTable.Declarations, isNamespaceReexportDeclaration) || !isLocalNameLookup) &&
|
|
||||||
// While exports are generally considered to be in scope, export-specifier declared symbols are _not_
|
|
||||||
// See similar comment in `resolveName` for details
|
|
||||||
(ignoreQualification || len(getDeclarationsOfKind(symbolFromSymbolTable, ast.KindExportSpecifier)) == 0) {
|
|
||||||
resolvedImportedSymbol := ch.resolveAlias(symbolFromSymbolTable)
|
|
||||||
candidate := ch.getCandidateListForSymbol(ctx, symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)
|
|
||||||
if len(candidate) > 0 {
|
|
||||||
candidateChains = append(candidateChains, candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if symbolFromSymbolTable.Name == ctx.symbol.Name && symbolFromSymbolTable.ExportSymbol != nil {
|
|
||||||
if ch.isAccessible(ctx, ch.getMergedSymbol(symbolFromSymbolTable.ExportSymbol) /*resolvedAliasSymbol*/, nil, ignoreQualification) {
|
|
||||||
candidateChains = append(candidateChains, []*ast.Symbol{ctx.symbol})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(candidateChains) > 0 {
|
|
||||||
// pick first, shortest
|
|
||||||
slices.SortStableFunc(candidateChains, ch.compareSymbolChains)
|
|
||||||
return candidateChains[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that
|
|
||||||
if reflect.ValueOf(ch.globals).UnsafePointer() == reflect.ValueOf(symbols).UnsafePointer() {
|
|
||||||
return ch.getCandidateListForSymbol(ctx, ch.globalThisSymbol, ch.globalThisSymbol, ignoreQualification)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) compareSymbolChainsWorker(a []*ast.Symbol, b []*ast.Symbol) int {
|
|
||||||
chainLen := len(a) - len(b)
|
|
||||||
if chainLen != 0 {
|
|
||||||
return chainLen
|
|
||||||
}
|
|
||||||
|
|
||||||
idx := 0
|
|
||||||
for idx < len(a) {
|
|
||||||
comparison := ch.compareSymbols(a[idx], b[idx])
|
|
||||||
if comparison != 0 {
|
|
||||||
return comparison
|
|
||||||
}
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func isUMDExportSymbol(symbol *ast.Symbol) bool {
|
|
||||||
return symbol != nil && len(symbol.Declarations) > 0 && symbol.Declarations[0] != nil && ast.IsNamespaceExportDeclaration(symbol.Declarations[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNamespaceReexportDeclaration(node *ast.Node) bool {
|
|
||||||
return ast.IsNamespaceExport(node) && node.Parent.AsExportDeclaration().ModuleSpecifier != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) getCandidateListForSymbol(
|
|
||||||
ctx accessibleSymbolChainContext,
|
|
||||||
symbolFromSymbolTable *ast.Symbol,
|
|
||||||
resolvedImportedSymbol *ast.Symbol,
|
|
||||||
ignoreQualification bool,
|
|
||||||
) []*ast.Symbol {
|
|
||||||
if ch.isAccessible(ctx, symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification) {
|
|
||||||
return []*ast.Symbol{symbolFromSymbolTable}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
|
|
||||||
// but only if the symbolFromSymbolTable can be qualified
|
|
||||||
candidateTable := ch.getExportsOfSymbol(resolvedImportedSymbol)
|
|
||||||
if candidateTable == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
accessibleSymbolsFromExports := ch.getAccessibleSymbolChainFromSymbolTable(ctx, candidateTable /*ignoreQualification*/, true, false)
|
|
||||||
if len(accessibleSymbolsFromExports) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !ch.canQualifySymbol(ctx, symbolFromSymbolTable, getQualifiedLeftMeaning(ctx.meaning)) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return append([]*ast.Symbol{symbolFromSymbolTable}, accessibleSymbolsFromExports...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) isAccessible(
|
|
||||||
ctx accessibleSymbolChainContext,
|
|
||||||
symbolFromSymbolTable *ast.Symbol,
|
|
||||||
resolvedAliasSymbol *ast.Symbol,
|
|
||||||
ignoreQualification bool,
|
|
||||||
) bool {
|
|
||||||
likeSymbols := false
|
|
||||||
if ctx.symbol == resolvedAliasSymbol {
|
|
||||||
likeSymbols = true
|
|
||||||
}
|
|
||||||
if ctx.symbol == symbolFromSymbolTable {
|
|
||||||
likeSymbols = true
|
|
||||||
}
|
|
||||||
symbol := ch.getMergedSymbol(ctx.symbol)
|
|
||||||
if symbol == ch.getMergedSymbol(resolvedAliasSymbol) {
|
|
||||||
likeSymbols = true
|
|
||||||
}
|
|
||||||
if symbol == ch.getMergedSymbol(symbolFromSymbolTable) {
|
|
||||||
likeSymbols = true
|
|
||||||
}
|
|
||||||
if !likeSymbols {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table)
|
|
||||||
// and if symbolFromSymbolTable or alias resolution matches the symbol,
|
|
||||||
// check the symbol can be qualified, it is only then this symbol is accessible
|
|
||||||
return !core.Some(symbolFromSymbolTable.Declarations, hasNonGlobalAugmentationExternalModuleSymbol) &&
|
|
||||||
(ignoreQualification || ch.canQualifySymbol(ctx, ch.getMergedSymbol(symbolFromSymbolTable), ctx.meaning))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) canQualifySymbol(
|
|
||||||
ctx accessibleSymbolChainContext,
|
|
||||||
symbolFromSymbolTable *ast.Symbol,
|
|
||||||
meaning ast.SymbolFlags,
|
|
||||||
) bool {
|
|
||||||
// If the symbol is equivalent and doesn't need further qualification, this symbol is accessible
|
|
||||||
return !ch.needsQualification(symbolFromSymbolTable, ctx.enclosingDeclaration, meaning) ||
|
|
||||||
// If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too
|
|
||||||
len(ch.getAccessibleSymbolChainEx(accessibleSymbolChainContext{symbolFromSymbolTable.Parent, ctx.enclosingDeclaration, getQualifiedLeftMeaning(meaning), ctx.useOnlyExternalAliasing, ctx.visitedSymbolTablesMap})) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) needsQualification(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags) bool {
|
|
||||||
qualify := false
|
|
||||||
ch.someSymbolTableInScope(enclosingDeclaration, func(symbolTable ast.SymbolTable, _ bool, _ bool, _ *ast.Node) bool {
|
|
||||||
// If symbol of this name is not available in the symbol table we are ok
|
|
||||||
res, ok := symbolTable[symbol.Name]
|
|
||||||
if !ok || res == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
symbolFromSymbolTable := ch.getMergedSymbol(res)
|
|
||||||
if symbolFromSymbolTable == nil {
|
|
||||||
// Continue to the next symbol table
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// If the symbol with this name is present it should refer to the symbol
|
|
||||||
if symbolFromSymbolTable == symbol {
|
|
||||||
// No need to qualify
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Qualify if the symbol from symbol table has same meaning as expected
|
|
||||||
shouldResolveAlias := symbolFromSymbolTable.Flags&ast.SymbolFlagsAlias != 0 && ast.GetDeclarationOfKind(symbolFromSymbolTable, ast.KindExportSpecifier) == nil
|
|
||||||
if shouldResolveAlias {
|
|
||||||
symbolFromSymbolTable = ch.resolveAlias(symbolFromSymbolTable)
|
|
||||||
}
|
|
||||||
flags := symbolFromSymbolTable.Flags
|
|
||||||
if shouldResolveAlias {
|
|
||||||
flags = ch.getSymbolFlags(symbolFromSymbolTable)
|
|
||||||
}
|
|
||||||
if flags&meaning != 0 {
|
|
||||||
qualify = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue to the next symbol table
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return qualify
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPropertyOrMethodDeclarationSymbol(symbol *ast.Symbol) bool {
|
|
||||||
if len(symbol.Declarations) > 0 {
|
|
||||||
for _, declaration := range symbol.Declarations {
|
|
||||||
switch declaration.Kind {
|
|
||||||
case ast.KindPropertyDeclaration,
|
|
||||||
ast.KindMethodDeclaration,
|
|
||||||
ast.KindGetAccessor,
|
|
||||||
ast.KindSetAccessor:
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *Checker) someSymbolTableInScope(
|
|
||||||
enclosingDeclaration *ast.Node,
|
|
||||||
callback func(symbolTable ast.SymbolTable, ignoreQualification bool, isLocalNameLookup bool, scopeNode *ast.Node) bool,
|
|
||||||
) bool {
|
|
||||||
for location := enclosingDeclaration; location != nil; location = location.Parent {
|
|
||||||
// Locals of a source file are not in scope (because they get merged into the global symbol table)
|
|
||||||
if canHaveLocals(location) && location.Locals() != nil && !ast.IsGlobalSourceFile(location) {
|
|
||||||
if callback(location.Locals(), false, true, location) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch location.Kind {
|
|
||||||
case ast.KindSourceFile, ast.KindModuleDeclaration:
|
|
||||||
if ast.IsSourceFile(location) && !ast.IsExternalOrCommonJSModule(location.AsSourceFile()) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
sym := ch.getSymbolOfDeclaration(location)
|
|
||||||
if callback(sym.Exports, false, true, location) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration:
|
|
||||||
// Type parameters are bound into `members` lists so they can merge across declarations
|
|
||||||
// This is troublesome, since in all other respects, they behave like locals :cries:
|
|
||||||
// TODO: the below is shared with similar code in `resolveName` - in fact, rephrasing all this symbol
|
|
||||||
// lookup logic in terms of `resolveName` would be nice
|
|
||||||
// The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals
|
|
||||||
// These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would
|
|
||||||
// trigger resolving late-bound names, which we may already be in the process of doing while we're here!
|
|
||||||
var table ast.SymbolTable
|
|
||||||
sym := ch.getSymbolOfDeclaration(location)
|
|
||||||
// TODO: Should this filtered table be cached in some way?
|
|
||||||
for key, memberSymbol := range sym.Members {
|
|
||||||
if memberSymbol.Flags&(ast.SymbolFlagsType & ^ast.SymbolFlagsAssignment) != 0 {
|
|
||||||
if table == nil {
|
|
||||||
table = make(ast.SymbolTable)
|
|
||||||
}
|
|
||||||
table[key] = memberSymbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if table != nil && callback(table, false, false, location) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(ch.globals, false, true, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
|
|
||||||
*
|
|
||||||
* @param symbol a Symbol to check if accessible
|
|
||||||
* @param enclosingDeclaration a Node containing reference to the symbol
|
|
||||||
* @param meaning a SymbolFlags to check if such meaning of the symbol is accessible
|
|
||||||
* @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (c *Checker) IsSymbolAccessible(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags, shouldComputeAliasesToMakeVisible bool) printer.SymbolAccessibilityResult {
|
|
||||||
return c.isSymbolAccessibleWorker(symbol, enclosingDeclaration, meaning, shouldComputeAliasesToMakeVisible, true /*allowModules*/)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) isSymbolAccessibleWorker(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags, shouldComputeAliasesToMakeVisible bool, allowModules bool) printer.SymbolAccessibilityResult {
|
|
||||||
if symbol != nil && enclosingDeclaration != nil {
|
|
||||||
result := c.IsAnySymbolAccessible([]*ast.Symbol{symbol}, enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible, allowModules)
|
|
||||||
if result != nil {
|
|
||||||
return *result
|
|
||||||
}
|
|
||||||
|
|
||||||
// This could be a symbol that is not exported in the external module
|
|
||||||
// or it could be a symbol from different external module that is not aliased and hence cannot be named
|
|
||||||
symbolExternalModule := core.FirstNonNil(symbol.Declarations, c.getExternalModuleContainer)
|
|
||||||
if symbolExternalModule != nil {
|
|
||||||
enclosingExternalModule := c.getExternalModuleContainer(enclosingDeclaration)
|
|
||||||
if symbolExternalModule != enclosingExternalModule {
|
|
||||||
// name from different external module that is not visible
|
|
||||||
return printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityCannotBeNamed,
|
|
||||||
ErrorSymbolName: c.symbolToStringEx(symbol, enclosingDeclaration, meaning, SymbolFormatFlagsAllowAnyNodeKind),
|
|
||||||
ErrorModuleName: c.symbolToString(symbolExternalModule),
|
|
||||||
ErrorNode: core.IfElse(ast.IsInJSFile(enclosingDeclaration), enclosingDeclaration, nil),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just a local name that is not accessible
|
|
||||||
return printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityNotAccessible,
|
|
||||||
ErrorSymbolName: c.symbolToStringEx(symbol, enclosingDeclaration, meaning, SymbolFormatFlagsAllowAnyNodeKind),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return printer.SymbolAccessibilityResult{
|
|
||||||
Accessibility: printer.SymbolAccessibilityAccessible,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
package checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
|
|
||||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/nodebuilder"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SymbolTrackerImpl struct {
|
|
||||||
context *NodeBuilderContext
|
|
||||||
inner nodebuilder.SymbolTracker
|
|
||||||
DisableTrackSymbol bool
|
|
||||||
tchost Host
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSymbolTrackerImpl(context *NodeBuilderContext, tracker nodebuilder.SymbolTracker, tchost Host) *SymbolTrackerImpl {
|
|
||||||
if tracker != nil {
|
|
||||||
for {
|
|
||||||
t, ok := tracker.(*SymbolTrackerImpl)
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
tracker = t.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &SymbolTrackerImpl{context, tracker, false, tchost}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) GetModuleSpecifierGenerationHost() modulespecifiers.ModuleSpecifierGenerationHost {
|
|
||||||
if this.inner == nil {
|
|
||||||
return this.tchost
|
|
||||||
}
|
|
||||||
return this.inner.GetModuleSpecifierGenerationHost()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) TrackSymbol(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags) bool {
|
|
||||||
if !this.DisableTrackSymbol {
|
|
||||||
if this.inner != nil && this.inner.TrackSymbol(symbol, enclosingDeclaration, meaning) {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Skip recording type parameters as they dont contribute to late painted statements
|
|
||||||
if symbol.Flags&ast.SymbolFlagsTypeParameter == 0 {
|
|
||||||
this.context.trackedSymbols = append(this.context.trackedSymbols, &TrackedSymbolArgs{symbol, enclosingDeclaration, meaning})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportInaccessibleThisError() {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportInaccessibleThisError()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportPrivateInBaseOfClassExpression(propertyName string) {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportPrivateInBaseOfClassExpression(propertyName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportInaccessibleUniqueSymbolError() {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportInaccessibleUniqueSymbolError()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportCyclicStructureError() {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportCyclicStructureError()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportLikelyUnsafeImportRequiredError(specifier string) {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportLikelyUnsafeImportRequiredError(specifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportTruncationError() {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportTruncationError()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportNonlocalAugmentation(containingFile *ast.SourceFile, parentSymbol *ast.Symbol, augmentingSymbol *ast.Symbol) {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportNonlocalAugmentation(containingFile, parentSymbol, augmentingSymbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportNonSerializableProperty(propertyName string) {
|
|
||||||
this.onDiagnosticReported()
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportNonSerializableProperty(propertyName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) onDiagnosticReported() {
|
|
||||||
this.context.reportedDiagnostic = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) ReportInferenceFallback(node *ast.Node) {
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.ReportInferenceFallback(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) PushErrorFallbackNode(node *ast.Node) {
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.PushErrorFallbackNode(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *SymbolTrackerImpl) PopErrorFallbackNode() {
|
|
||||||
if this.inner == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.inner.PopErrorFallbackNode()
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user