diff --git a/server/src/compiler_analyzer/analyzer.ts b/server/src/compiler_analyzer/analyzer.ts index 551f6503..d81b5b55 100644 --- a/server/src/compiler_analyzer/analyzer.ts +++ b/server/src/compiler_analyzer/analyzer.ts @@ -90,7 +90,6 @@ import { resolvedBuiltinDouble, resolvedBuiltinFloat, resolvedBuiltinInt, - resolvedBuiltinString, tryGetBuiltInType } from "./symbolBuiltin"; import {ComplementKind, pushHintOfCompletionScopeToParent} from "./symbolComplement"; @@ -873,7 +872,8 @@ function analyzeLiteral(scope: SymbolScope, literal: NodeLiteral): ResolvedType } if (literalValue.kind === TokenKind.String) { - return resolvedBuiltinString; + const stringType = scope.getBuiltinStringType(); + return stringType === undefined ? undefined : new ResolvedType(stringType); } if (literalValue.text === 'true' || literalValue.text === 'false') { @@ -1306,6 +1306,8 @@ export interface HoistResult { export function analyzeAfterHoisted(path: string, hoistResult: HoistResult): AnalyzedScope { const {globalScope, analyzeQueue} = hoistResult; + globalScope.commitContext(); + // Analyze the contents of the scope to be processed. while (analyzeQueue.length > 0) { const next = analyzeQueue.shift(); diff --git a/server/src/compiler_analyzer/checkType.ts b/server/src/compiler_analyzer/checkType.ts index a1dbff0d..230dce66 100644 --- a/server/src/compiler_analyzer/checkType.ts +++ b/server/src/compiler_analyzer/checkType.ts @@ -145,15 +145,6 @@ function canDownCast( return false; } -// Judge if the class has a metadata that indicates it is a built-in string type. -function isSourceBuiltinString(source: TypeSourceNode | undefined): boolean { - if (source === undefined) return false; - if (source.nodeName != NodeName.Class) return false; - - const builtinStringMetadata = "BuiltinString"; - return source.metadata.length === 1 && source.metadata[0].text === builtinStringMetadata; -} - function canCastFromPrimitiveType( srcType: SymbolType, destType: SymbolType ) { @@ -164,12 +155,6 @@ function canCastFromPrimitiveType( return destType.isTypeParameter && isSameToken(srcType.declaredPlace, destType.declaredPlace); } - if (srcType.identifierText === 'string') { // TODO: fix this - const destName = destType.declaredPlace.text; - if (isSourceBuiltinString(destNode)) return true; - return getGlobalSettings().builtinStringTypes.includes(destName); - } - if (srcType.identifierText === 'void') { return false; } diff --git a/server/src/compiler_analyzer/symbolBuiltin.ts b/server/src/compiler_analyzer/symbolBuiltin.ts index 2ac249d8..838f197d 100644 --- a/server/src/compiler_analyzer/symbolBuiltin.ts +++ b/server/src/compiler_analyzer/symbolBuiltin.ts @@ -24,10 +24,9 @@ const builtinNumberTypeMap: Map = (() => { return map; })(); -// TODO: Remove this? -export const builtinStringType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.String, 'string')); +// export const builtinStringType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.String, 'string')); -export const resolvedBuiltinString: ResolvedType = new ResolvedType(builtinStringType); +// export const resolvedBuiltinString: ResolvedType = new ResolvedType(builtinStringType); export const builtinIntType = builtinNumberTypeMap.get('int')!; diff --git a/server/src/compiler_analyzer/symbolScope.ts b/server/src/compiler_analyzer/symbolScope.ts index 75bf0a63..363e045e 100644 --- a/server/src/compiler_analyzer/symbolScope.ts +++ b/server/src/compiler_analyzer/symbolScope.ts @@ -2,7 +2,7 @@ import { SymbolOwnerNode, SymbolFunction, SymbolObject, - ReferencedSymbolInfo + ReferencedSymbolInfo, TypeSourceNode, SymbolType } from "./symbolObject"; import {diagnostic} from "../code/diagnostic"; import {NodeName} from "../compiler_parser/nodes"; @@ -10,26 +10,35 @@ import {ParserToken} from "../compiler_parser/parserToken"; import {getPathOfScope} from "./symbolUtils"; import {ComplementHints} from "./symbolComplement"; import assert = require("node:assert"); +import {getGlobalSettings} from "../code/settings"; export type ScopeMap = Map; export type SymbolMap = Map; +interface RootScopeContext { + builtinStringType: SymbolType | undefined; +} + /** * Represents a scope that contains symbols. */ export class SymbolScope { + // A node associated with this scope private symbolOwnerNode: SymbolOwnerNode | undefined; + // The parent scope of this scope. If this is the root scope (global scope), it has the context for the file. + private readonly parentOrContext: SymbolScope | RootScopeContext; public constructor( ownerNode: SymbolOwnerNode | undefined, - public readonly parentScope: SymbolScope | undefined, + parentScope: SymbolScope | undefined, public readonly key: string, public readonly childScopes: ScopeMap, public readonly symbolMap: SymbolMap, public readonly referencedList: ReferencedSymbolInfo[], public readonly completionHints: ComplementHints[], ) { + this.parentOrContext = parentScope ?? {builtinStringType: undefined}; this.symbolOwnerNode = ownerNode; } @@ -48,6 +57,11 @@ export class SymbolScope { []); } + public get parentScope(): SymbolScope | undefined { + if (this.parentOrContext instanceof SymbolScope) return this.parentOrContext; + return undefined; + } + public setOwnerNode(ownerNode: SymbolOwnerNode | undefined) { assert(this.symbolOwnerNode === undefined); this.symbolOwnerNode = ownerNode; @@ -57,6 +71,44 @@ export class SymbolScope { return this.symbolOwnerNode; } + /** + * Cache information in the context of the file + */ + public commitContext() { + assert(this.parentOrContext instanceof SymbolScope === false); + this.parentOrContext.builtinStringType = findBuiltinStringType(this); + } + + public getBuiltinStringType(): SymbolType | undefined { + if (this.parentOrContext instanceof SymbolScope) return this.parentOrContext.getBuiltinStringType(); + return this.parentOrContext.builtinStringType; + } +} + +function findBuiltinStringType(scope: SymbolScope): SymbolType | undefined { + for (const [key, symbol] of scope.symbolMap) { + if (symbol instanceof SymbolType && isSourceBuiltinString(symbol.sourceNode)) return symbol; + } + + for (const [key, child] of scope.childScopes) { + const found = findBuiltinStringType(child); + if (found !== undefined) return found; + } + + return undefined; +} + +// Judge if the class has a metadata that indicates it is a built-in string type. +function isSourceBuiltinString(source: TypeSourceNode | undefined): boolean { + if (source === undefined) return false; + if (source.nodeName != NodeName.Class) return false; + + // Check if the class has a metadata that indicates it is a built-in string type. + const builtinStringMetadata = "BuiltinString"; + if (source.metadata.length === 1 && source.metadata[0].text === builtinStringMetadata) return true; + + // Check whether the class name is a built-in string type with global settings. + return getGlobalSettings().builtinStringTypes.includes(source.identifier.text); } export interface SymbolAndScope {