remove unused packages
This commit is contained in:
parent
0cea2e734b
commit
78201db012
@ -1,8 +1,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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