Preserve Gotlin semantics across packages

This commit is contained in:
pavel 2026-08-27 22:18:45 +02:00
commit acb42a5702
10 changed files with 525 additions and 34 deletions

View file

@ -56,6 +56,14 @@ type ClassSymbol struct {
Methods map[string]*Symbol
}
type PackageSymbol struct {
Alias string
Metadata *PackageMetadata
Classes map[string]*ClassSymbol
Functions map[string]*Symbol
Enums map[string]EnumDecl
}
type SemanticProgram struct {
Syntax *Program
Global *Scope
@ -69,6 +77,7 @@ type SemanticProgram struct {
Mappings *mappingState
Diagnostics []SemanticDiagnostic
FunctionEffects map[string]Effect
Packages map[string]*PackageSymbol
}
func Analyze(program *Program) (*SemanticProgram, error) {
@ -80,7 +89,19 @@ func Analyze(program *Program) (*SemanticProgram, error) {
}
func AnalyzeWithContext(program *Program, additional []*Program) (*SemanticProgram, []SemanticDiagnostic) {
semantic, err := analyzeProgram(program, additional)
return analyzeWithMetadata(program, additional, nil)
}
func AnalyzeWithContextAndMetadata(program *Program, additional []*Program, metadata []*PackageMetadata) (*SemanticProgram, []SemanticDiagnostic) {
return analyzeWithMetadata(program, additional, metadata)
}
func AnalyzeWithMetadata(program *Program, metadata []*PackageMetadata) (*SemanticProgram, []SemanticDiagnostic) {
return analyzeWithMetadata(program, nil, metadata)
}
func analyzeWithMetadata(program *Program, additional []*Program, metadata []*PackageMetadata) (*SemanticProgram, []SemanticDiagnostic) {
semantic, err := analyzeProgram(program, additional, metadata)
if err != nil {
return semantic, []SemanticDiagnostic{diagnosticForError("semantic-error", err)}
}
@ -91,7 +112,7 @@ func AnalyzeWithContext(program *Program, additional []*Program) (*SemanticProgr
return semantic, nil
}
func analyzeProgram(program *Program, additional []*Program) (*SemanticProgram, error) {
func analyzeProgram(program *Program, additional []*Program, metadata []*PackageMetadata) (*SemanticProgram, error) {
semantic := &SemanticProgram{
Syntax: program,
Global: NewScope(nil),
@ -103,6 +124,7 @@ func analyzeProgram(program *Program, additional []*Program) (*SemanticProgram,
GoPackages: map[string]*gotypes.Package{},
Mappings: &mappingState{functions: map[string]string{}},
FunctionEffects: map[string]Effect{},
Packages: map[string]*PackageSymbol{},
}
programs := append([]*Program{program}, additional...)
for _, source := range programs {
@ -132,6 +154,9 @@ func analyzeProgram(program *Program, additional []*Program) (*SemanticProgram,
name = defaultImportAlias(imported)
}
semantic.Imports[name] = true
if packageMetadata := metadataForImport(imported, metadata); packageMetadata != nil {
semantic.Packages[name] = packageSymbolFromMetadata(name, packageMetadata)
}
if importedPackage, err := importGoPackage(imported); err == nil {
semantic.GoPackages[name] = importedPackage
}
@ -210,7 +235,7 @@ func (semantic *SemanticProgram) ResolveType(text string) (Type, error) {
if err != nil {
return nil, err
}
resolved := resolveClassTypes(typ, semantic.ClassInfo)
resolved := resolveImportedTypes(resolveClassTypes(typ, semantic.ClassInfo), semantic.Packages)
if err := validateNoClassPointer(resolved); err != nil {
return nil, err
}
@ -234,7 +259,7 @@ func (semantic *SemanticProgram) ResolveTypeRefWithParams(ref TypeRef, params []
for _, param := range params {
paramSet[param] = true
}
resolved := resolveClassTypes(resolveTypeParameters(typ, paramSet), semantic.ClassInfo)
resolved := resolveImportedTypes(resolveClassTypes(resolveTypeParameters(typ, paramSet), semantic.ClassInfo), semantic.Packages)
if err := validateNoClassPointer(resolved); err != nil {
return nil, err
}
@ -244,8 +269,11 @@ func (semantic *SemanticProgram) ResolveTypeRefWithParams(ref TypeRef, params []
func validateNoClassPointer(typ Type) error {
switch value := typ.(type) {
case GoPointerType:
if class, ok := value.Element.(ClassType); ok {
switch class := value.Element.(type) {
case ClassType:
return fmt.Errorf("Gotlin class %s is already reference-valued; remove '*'", class.Class.Name)
case ImportedClassType:
return fmt.Errorf("Gotlin class %s is already reference-valued; remove '*'", class.String())
}
return validateNoClassPointer(value.Element)
case NullableType: