diff --git a/server/src/compiler_analyzer/analyzer.ts b/server/src/compiler_analyzer/analyzer.ts index ec3ffa4a..551f6503 100644 --- a/server/src/compiler_analyzer/analyzer.ts +++ b/server/src/compiler_analyzer/analyzer.ts @@ -54,8 +54,6 @@ import { import { getSourceNodeName, isSourceNodeClassOrInterface, - isSourcePrimitiveType, - PrimitiveType, SymbolFunction, SymbolObject, SymbolType, @@ -516,7 +514,7 @@ function analyzeReturn(scope: SymbolScope, nodeReturn: NodeReturn) { } const expectedReturn = functionReturn.returnType?.symbolType; - if (expectedReturn instanceof SymbolType && expectedReturn?.definitionSource === PrimitiveType.Void) { + if (expectedReturn instanceof SymbolType && expectedReturn?.identifierText === 'void') { if (nodeReturn.assign === undefined) return; diagnostic.addError(getNodeLocation(nodeReturn.nodeRange), `Function does not return a value.`); } else { @@ -727,7 +725,7 @@ function analyzeBuiltinConstructorCaller( if (constructorType.sourceScope === undefined) return undefined; if (constructorType.symbolType instanceof SymbolType - && getSourceNodeName(constructorType.symbolType.definitionSource) === NodeName.Enum) { + && getSourceNodeName(constructorType.symbolType.sourceNode) === NodeName.Enum) { // Constructor for enum const argList = callerArgList.argList; if (argList.length != 1 || canTypeConvert( @@ -787,7 +785,7 @@ function analyzeExprPostOp1(scope: SymbolScope, exprPostOp: NodeExprPostOp1, exp const identifier = isMemberMethod ? member.identifier : member; if (identifier === undefined) return undefined; - if (isSourceNodeClassOrInterface(exprValue.symbolType.definitionSource) === false) { + if (isSourceNodeClassOrInterface(exprValue.symbolType.sourceNode) === false) { diagnostic.addError(identifier.location, `'${identifier.text}' is not a member.`); return undefined; } @@ -1130,7 +1128,7 @@ function analyzeOperatorAlias( return undefined; } - if (isSourcePrimitiveType(lhs.symbolType.definitionSource)) { + if (lhs.symbolType.isSystemType()) { diagnostic.addError( operator.location, `Operator '${alias}' of '${stringifyResolvedType(lhs)}' is not defined.`); @@ -1177,7 +1175,7 @@ function analyzeBitOp( assert(alias !== undefined); // If the left-hand side is a primitive type, use the operator of the right-hand side type - return lhs.symbolType instanceof SymbolType && isSourcePrimitiveType(lhs.symbolType.definitionSource) + return lhs.symbolType instanceof SymbolType && lhs.symbolType.isSystemType() ? analyzeOperatorAlias(scope, operator, rhs, lhs, rightRange, leftRange, alias[1]) : analyzeOperatorAlias(scope, operator, lhs, rhs, leftRange, rightRange, alias[0]); } @@ -1207,7 +1205,7 @@ function analyzeMathOp( assert(alias !== undefined); // If the left-hand side is a primitive type, use the operator of the right-hand side type - return lhs.symbolType instanceof SymbolType && isSourcePrimitiveType(lhs.symbolType.definitionSource) + return lhs.symbolType instanceof SymbolType && lhs.symbolType.isSystemType() ? analyzeOperatorAlias(scope, operator, rhs, lhs, rightRange, leftRange, alias[1]) : analyzeOperatorAlias(scope, operator, lhs, rhs, leftRange, rightRange, alias[0]); } @@ -1268,7 +1266,7 @@ function analyzeAssignOp( ): ResolvedType | undefined { if (lhs === undefined || rhs === undefined) return undefined; if (lhs.symbolType instanceof SymbolType && rhs.symbolType instanceof SymbolType) { - if (lhs.symbolType.definitionSource === PrimitiveType.Number && rhs.symbolType.definitionSource === PrimitiveType.Number) return lhs; + if (lhs.symbolType.isNumberType() && rhs.symbolType.isNumberType()) return lhs; } if (operator.text === '=') { diff --git a/server/src/compiler_analyzer/checkConversion.ts b/server/src/compiler_analyzer/checkConversion.ts new file mode 100644 index 00000000..147b8255 --- /dev/null +++ b/server/src/compiler_analyzer/checkConversion.ts @@ -0,0 +1,100 @@ +/** + * Check if the source type can be converted to the destination type. + * @param src + * @param dest + */ +import {ResolvedType} from "./resolvedType"; +import {SymbolFunction} from "./symbolObject"; + +export enum ConversionType { + Implicit = 'Implicit', // asIC_IMPLICIT_CONV + ExplicitRefCast = 'ExplicitRefCast', // asIC_EXPLICIT_REF_CAST + ExplicitValueCast = 'ExplicitValue', // asIC_EXPLICIT_VAL_CAST +} + +enum ConversionConst { + NoConv = 0, + ConstConv = 1, + EnumSameSizeConv = 2, + EnumDiffSizeConv = 3, + PrimitiveSizeUpConv = 4, + PrimitiveSizeDownConv = 5, + SignedToUnsignedConv = 6, + UnsignedToSignedConv = 7, + IntToFloatConv = 8, + FloatToIntConv = 9, + RefConv = 10, + ObjToPrimitiveConv = 12, + ToObjectConv = 14, + VariableConv = 16, + + Unknown = 255, +} + +export function evaluateConversionCost( + src: ResolvedType | undefined, + dest: ResolvedType | undefined, + type: ConversionType = ConversionType.Implicit +) { + if (src === undefined || dest === undefined) return ConversionConst.Unknown; + + const srcType = src.symbolType; + const destType = dest.symbolType; + + if (srcType instanceof SymbolFunction || destType instanceof SymbolFunction) { + // TODO + return ConversionConst.NoConv; + } + + // FIXME: Handle init list? + + if (srcType.identifierText === 'void') return ConversionConst.NoConv; + + // FIXME? + if (srcType.identifierText === '?') return ConversionConst.VariableConv; + if (srcType.identifierText === 'auto') return ConversionConst.VariableConv; + + if (destType.isSystemType()) { + // Destination is a primitive type + if (srcType.isSystemType()) { + // Source is a primitive type + return evaluateConvPrimitiveToPrimitive(src, dest, type); + } else { + // Source is an object type + return evaluateConvObjectToPrimitive(src, dest, type); + } + } else { + // Destination is a user-defined type + // TODO + } + + return ConversionConst.NoConv; +} + +function evaluateConvPrimitiveToPrimitive( + src: ResolvedType, + dest: ResolvedType, + type: ConversionType, +) { + // const srcType = src.symbolType.identifierText; + return ConversionConst.PrimitiveSizeUpConv; +} + +// TODO: Use this for evaluating object to primitive +const numberConversionCostTable = new Map([ + ['double', ['float', 'int64', 'uint64', 'int', 'uint', 'int16', 'uint16', 'int8', 'uint8']], + ['float', ['double', 'int64', 'uint64', 'int', 'uint', 'int16', 'uint16', 'int8', 'uint8']], + ['int64', ['uint64', 'int', 'uint', 'int16', 'uint16', 'int8', 'uint8', 'double', 'float']], + ['uint64', ['int64', 'uint', 'int', 'uint16', 'int16', 'uint8', 'int8', 'double', 'float']], + ['int', ['uint', 'int64', 'uint64', 'int16', 'uint16', 'int8', 'uint8', 'double', 'float']], + ['uint', ['int', 'uint64', 'int64', 'uint16', 'int16', 'uint8', 'int8', 'double', 'float']], + ['int16', ['uint16', 'int', 'uint', 'int64', 'uint64', 'int8', 'uint8', 'double', 'float']], + ['uint16', ['int16', 'uint', 'int', 'uint64', 'int64', 'uint8', 'int8', 'double', 'float']], + ['int8', ['uint8', 'int16', 'uint16', 'int', 'uint', 'int64', 'uint64', 'double', 'float']], + ['uint8', ['int8', 'uint16', 'int16', 'uint', 'int', 'uint64', 'int64', 'double', 'float']], +]); + +function evaluateConvObjectToPrimitive(src: ResolvedType, dest: ResolvedType, type: ConversionType) { + // TODO + return ConversionConst.ObjToPrimitiveConv; +} diff --git a/server/src/compiler_analyzer/checkType.ts b/server/src/compiler_analyzer/checkType.ts index cae25c47..a1dbff0d 100644 --- a/server/src/compiler_analyzer/checkType.ts +++ b/server/src/compiler_analyzer/checkType.ts @@ -1,10 +1,8 @@ import { - isSourcePrimitiveType, - PrimitiveType, - DefinitionSource, + TypeSourceNode, SymbolFunction, SymbolObject, - SymbolType, + SymbolType, isSourceNodeClassOrInterface, } from "./symbolObject"; import {AccessModifier, NodeName, ParsedRange} from "../compiler_parser/nodes"; import {getNodeLocation} from "../compiler_parser/nodesUtils"; @@ -14,6 +12,7 @@ import assert = require("assert"); import {findSymbolShallowly, resolveTemplateType, stringifyResolvedType} from "./symbolUtils"; import {getGlobalSettings} from "../code/settings"; import {ResolvedType} from "./resolvedType"; +import {isSameToken} from "../compiler_tokenizer/tokenUtils"; /** * Check if the source type can be converted to the destination type. @@ -29,7 +28,9 @@ export function checkTypeMatch( ): boolean { if (canTypeConvert(src, dest)) return true; - diagnostic.addError(getNodeLocation(nodeRange), `'${stringifyResolvedType(src)}' cannot be converted to '${stringifyResolvedType(dest)}'.`); + diagnostic.addError( + getNodeLocation(nodeRange), + `'${stringifyResolvedType(src)}' cannot be converted to '${stringifyResolvedType(dest)}'.`); return false; } @@ -67,7 +68,7 @@ function isTypeMatchInternal( // Are we trying to pass something into ? if (destType instanceof SymbolType) - if (destType.definitionSource === PrimitiveType.Any) return true; + if (destType.identifierText === '?') return true; // if (dest.isHandler === false) return false; // FIXME: Handler Checking? return isFunctionHandlerMatch(srcType, destType); @@ -75,19 +76,19 @@ function isTypeMatchInternal( return false; } - const srcNode = srcType.definitionSource; - const destNode = destType.definitionSource; + const srcNode = srcType.sourceNode; + const destNode = destType.sourceNode; - if (destNode === PrimitiveType.Any || destNode === PrimitiveType.Auto) return true; + if (destType.identifierText === '?' || destType.identifierText === 'auto') return true; - if (isSourcePrimitiveType(srcNode)) { + if (srcType.isSystemType()) { // Succeeds if it can be cast from one primitive type to another primitive type. if (canCastFromPrimitiveType(srcType, destType)) return true; } else { // Succeeds if they both point to the same type. if (srcType.declaredPlace === destType.declaredPlace) return true; - if (srcNode.nodeName === NodeName.Enum && destNode === PrimitiveType.Number) return true; + if (srcNode?.nodeName === NodeName.Enum && destType.isNumberType()) return true; // Succeeds if any of the inherited types in the source match the destination. if (canDownCast(srcType, destType)) return true; @@ -104,7 +105,7 @@ function isTypeMatchInternal( } // Fails if the destination type is not a class. - if (isSourcePrimitiveType(destNode) || destNode.nodeName !== NodeName.Class) return false; + if (destType.isSystemType() || destNode?.nodeName !== NodeName.Class) return false; // Determine if it matches the constructor. const destIdentifier = destNode.identifier.text; @@ -127,12 +128,12 @@ function isFunctionHandlerMatch(srcType: SymbolFunction, destType: SymbolType | function canDownCast( srcType: SymbolType, destType: SymbolType ): boolean { - const srcNode = srcType.definitionSource; - if (isSourcePrimitiveType(srcNode)) return false; + const srcNode = srcType.sourceNode; + if (srcType.isSystemType()) return false; - if (srcType.definitionSource === destType.definitionSource) return true; + if (srcType.sourceNode === destType.sourceNode) return true; - if (srcNode.nodeName === NodeName.Class || srcNode.nodeName === NodeName.Interface) { + if (isSourceNodeClassOrInterface(srcNode)) { if (srcType.baseList === undefined) return false; for (const srcBase of srcType.baseList) { if (srcBase?.symbolType === undefined) continue; @@ -145,9 +146,8 @@ function canDownCast( } // Judge if the class has a metadata that indicates it is a built-in string type. -function isSourceBuiltinString(source: DefinitionSource): boolean { - if (isSourcePrimitiveType(source)) return false; - +function isSourceBuiltinString(source: TypeSourceNode | undefined): boolean { + if (source === undefined) return false; if (source.nodeName != NodeName.Class) return false; const builtinStringMetadata = "BuiltinString"; @@ -157,30 +157,33 @@ function isSourceBuiltinString(source: DefinitionSource): boolean { function canCastFromPrimitiveType( srcType: SymbolType, destType: SymbolType ) { - const srcNode = srcType.definitionSource; - const destNode = destType.definitionSource; + const srcNode = srcType.sourceNode; + const destNode = destType.sourceNode; + + if (srcType.isTypeParameter) { + return destType.isTypeParameter && isSameToken(srcType.declaredPlace, destType.declaredPlace); + } - switch (srcNode) { - case PrimitiveType.Template: - return destNode === PrimitiveType.Template && srcType.declaredPlace === destType.declaredPlace; - case PrimitiveType.String: { + if (srcType.identifierText === 'string') { // TODO: fix this const destName = destType.declaredPlace.text; if (isSourceBuiltinString(destNode)) return true; return getGlobalSettings().builtinStringTypes.includes(destName); } - case PrimitiveType.Void: + + if (srcType.identifierText === 'void') { return false; - case PrimitiveType.Number: - return destType.definitionSource === PrimitiveType.Number; - case PrimitiveType.Bool: - return destType.definitionSource === PrimitiveType.Bool; - case PrimitiveType.Any: - return true; - case PrimitiveType.Auto: - return true; - default: - assert(false); } + + if (srcType.isNumberType()) { + return destType.isNumberType(); + } + + if (srcType.identifierText === 'bool') { + return destType.identifierText === 'bool'; + } + + // FIXME? + return true; } function canConstructImplicitly( @@ -198,16 +201,18 @@ function canConstructImplicitly( const constructor = findSymbolShallowly(constructorScope, destIdentifier); if (constructor === undefined || constructor instanceof SymbolFunction === false) return false; - return canConstructBy(constructor, srcType.definitionSource); + if (srcType.sourceNode === undefined) return true; // FIXME? + + return canConstructBy(constructor, srcType.sourceNode); } -function canConstructBy(constructor: SymbolFunction, srcType: DefinitionSource): boolean { +function canConstructBy(constructor: SymbolFunction, srcType: TypeSourceNode): boolean { // Succeeds if the constructor has one argument and that argument matches the source type. if (constructor.parameterTypes.length === 1) { const paramType = constructor.parameterTypes[0]; if (paramType !== undefined && paramType.symbolType instanceof SymbolType - && paramType.symbolType.definitionSource === srcType + && paramType.symbolType.sourceNode === srcType ) { return true; } diff --git a/server/src/compiler_analyzer/hoist.ts b/server/src/compiler_analyzer/hoist.ts index c08f8e39..275f744a 100644 --- a/server/src/compiler_analyzer/hoist.ts +++ b/server/src/compiler_analyzer/hoist.ts @@ -15,7 +15,7 @@ import { ParsedEnumMember } from "../compiler_parser/nodes"; import {pushHintOfCompletionScopeToParent} from "./symbolComplement"; -import {PrimitiveType, SymbolFunction, SymbolType, SymbolVariable} from "./symbolObject"; +import {SymbolFunction, SymbolType, SymbolVariable} from "./symbolObject"; import {findSymbolWithParent, insertSymbolObject, tryInsertSymbolObject} from "./symbolUtils"; import {ResolvedType} from "./resolvedType"; import {getGlobalSettings} from "../code/settings"; @@ -84,7 +84,7 @@ function hoistEnum(parentScope: SymbolScope, nodeEnum: NodeEnum) { const symbol: SymbolType = SymbolType.create({ declaredPlace: nodeEnum.identifier, declaredScope: parentScope, - definitionSource: nodeEnum, + sourceNode: nodeEnum, membersScope: undefined, }); @@ -117,7 +117,7 @@ function hoistClass(parentScope: SymbolScope, nodeClass: NodeClass, analyzing: A const symbol: SymbolType = SymbolType.create({ declaredPlace: nodeClass.identifier, declaredScope: parentScope, - definitionSource: nodeClass, + sourceNode: nodeClass, membersScope: undefined, }); if (insertSymbolObject(parentScope.symbolMap, symbol) === false) return; @@ -172,8 +172,9 @@ function hoistClassTemplateTypes(scope: SymbolScope, types: NodeType[] | undefin insertSymbolObject(scope.symbolMap, SymbolType.create({ declaredPlace: getIdentifierInType(type), declaredScope: scope, - definitionSource: PrimitiveType.Template, + sourceNode: undefined, membersScope: undefined, + isTypeParameter: true, })); templateTypes.push(getIdentifierInType(type)); @@ -248,7 +249,7 @@ function hoistTypeDef(parentScope: SymbolScope, typeDef: NodeTypeDef) { const symbol: SymbolType = SymbolType.create({ declaredPlace: typeDef.identifier, declaredScope: parentScope, - definitionSource: builtInType.definitionSource, + sourceNode: builtInType.sourceNode, membersScope: undefined, }); insertSymbolObject(parentScope.symbolMap, symbol); @@ -312,7 +313,7 @@ function hoistInterface(parentScope: SymbolScope, nodeInterface: NodeInterface, const symbol: SymbolType = SymbolType.create({ declaredPlace: nodeInterface.identifier, declaredScope: parentScope, - definitionSource: nodeInterface, + sourceNode: nodeInterface, membersScope: undefined, }); if (insertSymbolObject(parentScope.symbolMap, symbol) === false) return; diff --git a/server/src/compiler_analyzer/resolvedType.ts b/server/src/compiler_analyzer/resolvedType.ts index ee27de61..965d04f2 100644 --- a/server/src/compiler_analyzer/resolvedType.ts +++ b/server/src/compiler_analyzer/resolvedType.ts @@ -7,7 +7,7 @@ import {SymbolFunction, SymbolType} from "./symbolObject"; */ export class ResolvedType { constructor( - public readonly symbolType: SymbolType | SymbolFunction, + public readonly symbolType: SymbolType | SymbolFunction, // TODO: rename? // public readonly sourceScope: SymbolScope | undefined, public readonly isHandler?: boolean, public readonly templateTranslate?: TemplateTranslation, diff --git a/server/src/compiler_analyzer/symbolBuiltin.ts b/server/src/compiler_analyzer/symbolBuiltin.ts index 131f9d27..2ac249d8 100644 --- a/server/src/compiler_analyzer/symbolBuiltin.ts +++ b/server/src/compiler_analyzer/symbolBuiltin.ts @@ -3,15 +3,15 @@ import {createSymbolScope} from "./symbolScope"; import {createVirtualToken} from "../compiler_tokenizer/tokenUtils"; import {TokenKind} from "../compiler_tokenizer/tokens"; import {numberTypeSet} from "../compiler_tokenizer/tokenReservedWords"; -import {PrimitiveType, SymbolType} from "./symbolObject"; +import {SymbolType} from "./symbolObject"; import assert = require("node:assert"); import {ResolvedType} from "./resolvedType"; -function createBuiltinType(virtualToken: ParserToken, name: PrimitiveType): SymbolType { +function createBuiltinType(virtualToken: ParserToken): SymbolType { return SymbolType.create({ declaredPlace: virtualToken, // The built-in type uses a virtual token declaredScope: createSymbolScope(undefined, undefined, ''), - definitionSource: name, + sourceNode: undefined, membersScope: undefined, }); } @@ -19,14 +19,13 @@ function createBuiltinType(virtualToken: ParserToken, name: PrimitiveType): Symb const builtinNumberTypeMap: Map = (() => { const map = new Map(); for (const name of numberTypeSet) { - map.set(name, createBuiltinType(createVirtualToken(TokenKind.Reserved, name), PrimitiveType.Number)); + map.set(name, createBuiltinType(createVirtualToken(TokenKind.Reserved, name))); } return map; })(); -export const builtinStringType: SymbolType = createBuiltinType( - createVirtualToken(TokenKind.String, 'string'), - PrimitiveType.String); +// TODO: Remove this? +export const builtinStringType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.String, 'string')); export const resolvedBuiltinString: ResolvedType = new ResolvedType(builtinStringType); @@ -48,23 +47,15 @@ function assignBuiltinNumberType(key: string): SymbolType { assert(false); } -export const builtinBoolType: SymbolType = createBuiltinType( - createVirtualToken(TokenKind.Reserved, 'bool'), - PrimitiveType.Bool); +export const builtinBoolType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.Reserved, 'bool')); export const resolvedBuiltinBool: ResolvedType = new ResolvedType(builtinBoolType); -export const builtinVoidType: SymbolType = createBuiltinType( - createVirtualToken(TokenKind.Reserved, 'void'), - PrimitiveType.Void); +export const builtinVoidType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.Reserved, 'void')); -export const builtinAnyType: SymbolType = createBuiltinType( - createVirtualToken(TokenKind.Reserved, '?'), - PrimitiveType.Any); +export const builtinAnyType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.Reserved, '?')); -export const builtinAutoType: SymbolType = createBuiltinType( - createVirtualToken(TokenKind.Reserved, 'auto'), - PrimitiveType.Auto); +export const builtinAutoType: SymbolType = createBuiltinType(createVirtualToken(TokenKind.Reserved, 'auto')); export function tryGetBuiltInType(token: ParserToken): SymbolType | undefined { if (token.kind !== TokenKind.Reserved) return undefined; diff --git a/server/src/compiler_analyzer/symbolObject.ts b/server/src/compiler_analyzer/symbolObject.ts index 7e9e35a4..ce285a2c 100644 --- a/server/src/compiler_analyzer/symbolObject.ts +++ b/server/src/compiler_analyzer/symbolObject.ts @@ -18,38 +18,21 @@ import assert = require("node:assert"); import {Mutable} from "../utils/utilities"; import {ResolvedType} from "./resolvedType"; import {SymbolScope} from "./symbolScope"; - -export enum PrimitiveType { - Template = 'Template', - String = 'String', - Bool = 'Bool', - Number = 'Number', - Void = 'Void', - Any = 'Any', - Auto = 'Auto', -} - -/** - * The node that serves as the origin of a symbol's declaration. - * Types without a declaration node, such as built-in types, are represented using PrimitiveType. - */ -export type DefinitionSource = NodeEnum | NodeClass | NodeInterface | PrimitiveType; +import {TokenKind} from "../compiler_tokenizer/tokens"; +import {numberTypeSet} from "../compiler_tokenizer/tokenReservedWords"; /** - * Checks whether the given `DefinitionSource` is a `PrimitiveType`. - * In other words, returns `true` if the given `DefinitionSource` does not have a declaration node. + * The node that serves as the origin of a type declaration. */ -export function isSourcePrimitiveType(type: DefinitionSource | undefined): type is PrimitiveType { - return typeof type === 'string'; -} +export type TypeSourceNode = NodeEnum | NodeClass | NodeInterface; -export function isSourceNodeClassOrInterface(type: DefinitionSource): type is NodeClass { - if (isSourcePrimitiveType(type)) return false; +export function isSourceNodeClassOrInterface(type: TypeSourceNode | undefined): type is NodeClass { + if (type === undefined) return false; return type.nodeName === NodeName.Class || type.nodeName === NodeName.Interface; } -export function getSourceNodeName(type: DefinitionSource | undefined): NodeName | undefined { - if (type === undefined || isSourcePrimitiveType(type)) return undefined; +export function getSourceNodeName(type: TypeSourceNode | undefined): NodeName | undefined { + if (type === undefined) return undefined; return type.nodeName; } @@ -65,9 +48,12 @@ export class SymbolType implements SymbolBase { constructor( public readonly declaredPlace: ParserToken, public readonly declaredScope: SymbolScope, - public readonly definitionSource: DefinitionSource, + public readonly sourceNode: TypeSourceNode | undefined, public readonly membersScope: SymbolScope | undefined, - public readonly templateTypes?: ParserToken[], // e.g. + // Whether this is a template type parameter (i.e., true when this is 'T' in 'class array') + public readonly isTypeParameter?: boolean, + // Template type parameters (i.e., 'class A' has two template types 'T' and 'U') + public readonly templateTypes?: ParserToken[], public readonly baseList?: (ResolvedType | undefined)[], public readonly isHandler?: boolean, ) { @@ -76,15 +62,42 @@ export class SymbolType implements SymbolBase { public static create(args: { declaredPlace: ParserToken declaredScope: SymbolScope - definitionSource: DefinitionSource + sourceNode: TypeSourceNode | undefined membersScope: SymbolScope | undefined + isTypeParameter?: boolean + templateTypes?: ParserToken[] + baseList?: (ResolvedType | undefined)[] + isHandler?: boolean }) { - return new SymbolType(args.declaredPlace, args.declaredScope, args.definitionSource, args.membersScope); + return new SymbolType( + args.declaredPlace, + args.declaredScope, + args.sourceNode, + args.membersScope, + args.isTypeParameter, + args.templateTypes, + args.baseList, + args.isHandler); } public mutate(): Mutable { return this; } + + public get identifierText(): string { + return this.declaredPlace.text; + } + + /** + * Determine if the type is a system type. (e.g. int, float, void) + */ + public isSystemType(): boolean { + return this.sourceNode === undefined; + } + + public isNumberType(): boolean { + return this.declaredPlace.kind === TokenKind.Reserved && this.declaredPlace.property.isNumber; + } } export class SymbolFunction implements SymbolBase { diff --git a/server/src/compiler_analyzer/symbolUtils.ts b/server/src/compiler_analyzer/symbolUtils.ts index 7b18f66e..7296dd90 100644 --- a/server/src/compiler_analyzer/symbolUtils.ts +++ b/server/src/compiler_analyzer/symbolUtils.ts @@ -1,5 +1,4 @@ import { - PrimitiveType, SymbolFunction, SymbolObject, SymbolType, @@ -68,7 +67,7 @@ export function resolveTemplateType( if (type.symbolType instanceof SymbolFunction) return undefined; // FIXME: 関数ハンドラのテンプレート解決も必要? - if (type.symbolType.definitionSource !== PrimitiveType.Template) return type; + if (type.symbolType.isTypeParameter !== true) return type; if (templateTranslate.has(type.symbolType.declaredPlace)) { return templateTranslate.get(type.symbolType.declaredPlace); @@ -85,7 +84,7 @@ export function resolveTemplateTypes( } export function isResolvedAutoType(type: ResolvedType | undefined): boolean { - return type !== undefined && type.symbolType instanceof SymbolType && type.symbolType.definitionSource === PrimitiveType.Auto; + return type !== undefined && type.symbolType instanceof SymbolType && type.symbolType.identifierText === 'auto'; } export function stringifyScopeSuffix(scope: SymbolScope | undefined): string { diff --git a/server/src/services/completion.ts b/server/src/services/completion.ts index cffb60f5..97d95372 100644 --- a/server/src/services/completion.ts +++ b/server/src/services/completion.ts @@ -130,8 +130,8 @@ function searchMissingCompletion(scope: SymbolScope, completion: ComplementHints function symbolToCompletionKind(symbol: SymbolObject): CompletionItemKind { if (symbol instanceof SymbolType) { - if (typeof symbol.definitionSource === 'string') return CompletionItemKind.Keyword; - if (symbol.definitionSource.nodeName === NodeName.Enum) return CompletionItemKind.Enum; + if (symbol.isSystemType() || symbol.sourceNode === undefined) return CompletionItemKind.Keyword; + if (symbol.sourceNode.nodeName === NodeName.Enum) return CompletionItemKind.Enum; return CompletionItemKind.Class; } else if (symbol instanceof SymbolFunction) { return CompletionItemKind.Function;