1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Value } from './Value'; 17import { ArkMethod } from '../model/ArkMethod'; 18import { IntersectionType, Type, UnionType, UnknownType } from './Type'; 19import { IRInference } from '../common/IRInference'; 20import { ArkBaseModel } from '../model/ArkBaseModel'; 21import { ModelUtils } from '../common/ModelUtils'; 22import { ArkClass } from '../model/ArkClass'; 23 24/** 25 * abstract type expr represents the type operations of types or values. 26 * AbstractTypeExpr is different from AbstractExpr. 27 * @category core/base/typeExpr 28 * @extends Type 29 * @example 30 * ```typescript 31 * let a = number; 32 * type A = typeof a; 33 * let b: keyof typeof a; 34 * ``` 35 */ 36export abstract class AbstractTypeExpr extends Type { 37 abstract getUses(): Value[]; 38 39 abstract getType(): Type; 40 41 public inferType(arkMethod: ArkMethod): void { 42 return; 43 } 44} 45 46/** 47 * typeQuery type expr represents the get type of value with typeof. 48 * @category core/base/typeExpr 49 * @extends AbstractTypeExpr 50 * @example 51 ```typescript 52 // opValue is a and type A is number 53 let a = number; 54 type A = typeof a; 55 ``` 56 */ 57 58export class TypeQueryExpr extends AbstractTypeExpr { 59 private opValue: Value | ArkBaseModel; 60 private genericTypes?: Type[]; 61 62 constructor(opValue: Value | ArkBaseModel, generateTypes?: Type[]) { 63 super(); 64 this.opValue = opValue; 65 this.genericTypes = generateTypes; 66 } 67 68 public setOpValue(opValue: Value | ArkBaseModel): void { 69 this.opValue = opValue; 70 } 71 72 public getOpValue(): Value | ArkBaseModel { 73 return this.opValue; 74 } 75 76 public setGenerateTypes(types: Type[]): void { 77 this.genericTypes = types; 78 } 79 80 public getGenerateTypes(): Type[] | undefined { 81 return this.genericTypes; 82 } 83 84 public addGenericType(gType: Type): void { 85 if (!this.genericTypes) { 86 this.genericTypes = []; 87 } 88 this.genericTypes.push(gType); 89 } 90 91 public getUses(): Value[] { 92 const opValue = this.getOpValue(); 93 if (opValue instanceof ArkBaseModel) { 94 return []; 95 } 96 let uses: Value[] = []; 97 uses.push(opValue); 98 uses.push(...opValue.getUses()); 99 return uses; 100 } 101 102 public getType(): Type { 103 const opValue = this.getOpValue(); 104 if (opValue instanceof ArkBaseModel) { 105 return ModelUtils.parseArkBaseModel2Type(opValue) ?? UnknownType.getInstance(); 106 } 107 return opValue.getType(); 108 } 109 110 public getTypeString(): string { 111 const opValue = this.getOpValue(); 112 const gTypes = this.getGenerateTypes(); 113 const genericStr = gTypes && gTypes.length > 0 ? `<${gTypes.join(',')}>` : ''; 114 if (opValue instanceof ArkClass || opValue instanceof ArkMethod) { 115 return `typeof ${opValue.getSignature().toString()}${genericStr}`; 116 } 117 return `typeof ${opValue.toString()}${genericStr}`; 118 } 119 120 public inferType(arkMethod: ArkMethod): void { 121 IRInference.inferTypeQueryExpr(this, arkMethod); 122 } 123} 124 125/** 126 * keyof type expr represents the type operator with keyof. 127 * It should be an internal expr. 128 * the final type should be transferred to union type, unless it cannot find out all types within the union type. 129 * @category core/base/typeExpr 130 * @extends AbstractTypeExpr 131 * @example 132 ```typescript 133 // opType is {a: 1, b: 2} and type of A is KeyofTypeExpr, which can be transferred to union type {'a', 'b'} 134 type A = keyof {a: 1, b: 2}; 135 136 // opType is number and type of B is KeyofTypeExpr, which can be transferred to union type "toString" | "toFixed" | "toExponential" | ... 137 type B = keyof number; 138 ``` 139 */ 140export class KeyofTypeExpr extends AbstractTypeExpr { 141 private opType: Type; 142 143 constructor(opType: Type) { 144 super(); 145 this.opType = opType; 146 } 147 148 public getOpType(): Type { 149 return this.opType; 150 } 151 152 public setOpType(opType: Type): void { 153 this.opType = opType; 154 } 155 156 public getUses(): Value[] { 157 let uses: Value[] = []; 158 if (this.getOpType() instanceof TypeQueryExpr) { 159 uses.push(...(this.getOpType() as TypeQueryExpr).getUses()); 160 } 161 return uses; 162 } 163 164 public getType(): Type { 165 return this; 166 } 167 168 public getTypeString(): string { 169 if (this.getOpType() instanceof UnionType || this.getOpType() instanceof IntersectionType) { 170 return `keyof (${this.getOpType().toString()})`; 171 } 172 return `keyof ${this.getOpType().toString()}`; 173 } 174 175 public inferType(arkMethod: ArkMethod): void { 176 IRInference.inferKeyofTypeExpr(this, arkMethod); 177 } 178} 179