1 /**
2 * Copyright 2020-2022 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdlib>
18 #include <algorithm>
19 #include <functional>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include "ir/dtype.h"
27 #include "mindapi/base/type_id.h"
28 #include "utils/log_adapter.h"
29 #include "base/base.h"
30 #include "include/robin_hood.h"
31 #include "ir/dtype/container.h"
32 #include "ir/dtype/empty.h"
33 #include "ir/dtype/monad_type.h"
34 #include "ir/dtype/number.h"
35 #include "ir/dtype/ref.h"
36 #include "ir/dtype/tensor_type.h"
37 #include "ir/dtype/type.h"
38 #include "utils/hash_map.h"
39
40 namespace mindspore {
DeepCopy() const41 TypePtr TypeAny::DeepCopy() const { return kTypeAny; }
42
GetExcptionTypeString(TypeId id)43 std::string GetExcptionTypeString(TypeId id) {
44 static mindspore::HashMap<TypeId, std::string> type_id_to_string = {{kMetaTypeType, "MetaType"},
45 {kMetaTypeObject, "MetaTypeObject"},
46 {kObjectTypeNumber, "Number"},
47 {kObjectTypeRowTensorType, "RowTensor"},
48 {kObjectTypeCOOTensorType, "COOTensor"},
49 {kObjectTypeUndeterminedType, "Undetermined"},
50 {kObjectTypeClass, "Class"},
51 {kObjectTypeFunction, "Function"},
52 {kObjectTypeJTagged, "JTagged"},
53 {kObjectTypeSymbolicKeyType, "SymbolicKey"},
54 {kNumberTypeUInt, "uint"},
55 {kNumberTypeComplex, "Complex"},
56 {kNumberTypeInt4, "Int4"},
57 {kNumberTypeGLUInt, "GLUInt"},
58 {kObjectTypeMonad, "Monad"},
59 {kObjectTypeCSRTensorType, "CSRTensor"},
60 {kObjectTypeMapTensorType, "MapTensor"}};
61
62 auto it = type_id_to_string.find(id);
63 std::string type = "";
64 if (it != type_id_to_string.end()) {
65 type = it->second;
66 } else {
67 type = std::to_string(id);
68 }
69
70 return type;
71 }
72
TypeIdToType(TypeId id)73 TypePtr TypeIdToType(TypeId id) {
74 static mindspore::HashMap<TypeId, TypePtr> type_id_to_type = {{kNumberTypeFloat16, kFloat16},
75 {kNumberTypeFloat, kFloat32},
76 {kNumberTypeFloat32, kFloat32},
77 {kNumberTypeFloat64, kFloat64},
78 {kNumberTypeBFloat16, kBFloat16},
79 {kNumberTypeComplex64, kComplex64},
80 {kNumberTypeInt4, kInt4},
81 {kNumberTypeInt8, kInt8},
82 {kNumberTypeInt16, kInt16},
83 {kNumberTypeInt32, kInt32},
84 {kNumberTypeInt, kInt32},
85 {kNumberTypeInt64, kInt64},
86 {kNumberTypeUInt8, kUInt8},
87 {kNumberTypeUInt16, kUInt16},
88 {kNumberTypeUInt32, kUInt32},
89 {kNumberTypeUInt64, kUInt64},
90 {kNumberTypeBool, kBool},
91 {kNumberTypeComplex64, kComplex64},
92 {kNumberTypeComplex128, kComplex128},
93 {kMetaTypeExternal, kTypeExternal},
94 {kMetaTypeAny, kTypeAny},
95 {kMetaTypeNone, kTypeNone},
96 {kMetaTypeNull, kTypeNull},
97 {kMetaTypeEllipsis, kTypeEllipsis},
98 {kObjectTypeEnvType, kTypeEnv},
99 {kObjectTypeRefKey, kRefKeyType},
100 {kObjectTypeRef, kRefType},
101 {kMetaTypeTypeType, kTypeType},
102 {kObjectTypeClass, kClassType},
103 {kObjectTypeString, kString},
104 {kObjectTypeList, kList},
105 {kObjectTypeTuple, kTuple},
106 {kObjectTypeNumber, kNumber},
107 {kObjectTypeDictionary, kDict},
108 {kObjectTypeSlice, kSlice},
109 {kObjectTypeKeyword, kKeyword},
110 {kObjectTypeTensorType, kTensorType},
111 {kObjectTypeUMonad, kUMonadType},
112 {kObjectTypeIOMonad, kIOMonadType},
113 {kTypeUnknown, kTypeNone},
114 {kMetaTypeProblem, kTypeNone},
115 {kObjectTypeCSRTensorType, kCSRTensorType},
116 {kObjectTypeCOOTensorType, kCOOTensorType},
117 {kObjectTypeRowTensorType, kRowTensorType},
118 {kObjectTypeMapTensorType, kMapTensorType}};
119 const auto &it = type_id_to_type.find(id);
120 if (it == type_id_to_type.end()) {
121 MS_LOG(EXCEPTION) << "Not support the type: " << GetExcptionTypeString(id);
122 }
123 return it->second;
124 }
125
TypeIdToString(TypeId id,bool to_lower)126 std::string TypeIdToString(TypeId id, bool to_lower) {
127 switch (id) {
128 case TypeId::kNumberTypeFloat:
129 return "float";
130 case TypeId::kNumberTypeInt:
131 return "int";
132 case TypeId::kNumberTypeUInt:
133 return "uint";
134 default:
135 break;
136 }
137 auto type = TypeIdToType(id)->ToString();
138 if (to_lower) {
139 (void)std::transform(type.begin(), type.end(), type.begin(),
140 [](auto c) { return static_cast<char>(std::tolower(c)); });
141 }
142 return type;
143 }
144
UnitSizeInBytes(TypeId id)145 size_t UnitSizeInBytes(TypeId id) {
146 size_t bytes = 0;
147 size_t complex_factor = 2;
148 switch (id) {
149 case kNumberTypeBool:
150 case kNumberTypeInt4:
151 case kNumberTypeInt8:
152 case kNumberTypeUInt8:
153 bytes = sizeof(int8_t);
154 break;
155 case kNumberTypeInt16:
156 case kNumberTypeUInt16:
157 case kNumberTypeFloat16:
158 case kNumberTypeBFloat16:
159 bytes = sizeof(int16_t);
160 break;
161 case kNumberTypeInt:
162 case kNumberTypeUInt:
163 case kNumberTypeInt32:
164 case kNumberTypeUInt32:
165 case kNumberTypeFloat:
166 case kNumberTypeFloat32:
167 bytes = sizeof(int32_t);
168 break;
169 case kNumberTypeUInt64:
170 case kNumberTypeInt64:
171 case kNumberTypeFloat64:
172 bytes = sizeof(int64_t);
173 break;
174 case kNumberTypeComplex64:
175 bytes = sizeof(float) * complex_factor;
176 break;
177 case kNumberTypeComplex128:
178 bytes = sizeof(double) * complex_factor;
179 break;
180 case kObjectTypeString:
181 bytes = sizeof(std::string);
182 break;
183 case kMetaTypeNone:
184 case kMetaTypeTypeType:
185 case kTypeUnknown:
186 case kObjectTypeMonad:
187 case kObjectTypeUMonad:
188 case kObjectTypeIOMonad:
189 bytes = 0;
190 break;
191 default:
192 MS_LOG(EXCEPTION) << "Invalid types for UnitSizeInBytes : " << TypeIdToString(id) << ", type id: " << id;
193 }
194
195 return bytes;
196 }
197
198 namespace {
199 template <typename T>
StringToNumberType(const std::string & type_name,const std::string & num_type_name)200 TypePtr StringToNumberType(const std::string &type_name, const std::string &num_type_name) {
201 TypePtr type = nullptr;
202 if (type_name == num_type_name) {
203 type = std::make_shared<T>();
204 } else {
205 if (num_type_name.size() >= type_name.size()) {
206 MS_LOG(EXCEPTION) << "Convert type is error, type_name(" << type_name << "), num_type_name(" << num_type_name
207 << ")";
208 }
209 auto bits = std::stoi(type_name.substr(num_type_name.size()));
210 type = std::make_shared<T>(bits);
211 }
212 return type;
213 }
214
215 /// Cnvert a string(like "type1, type2, type3") to Vector(TypeID_1, TypeID_1, TypeID_1)
216 /// \param type_names
217 /// \param types The return types
218 /// \return : true, convert success; false, format error
StringToVectorOfType(const std::string & type_names,std::vector<TypePtr> * types)219 bool StringToVectorOfType(const std::string &type_names, std::vector<TypePtr> *types) {
220 if (type_names.length() == 0) {
221 return true;
222 }
223 std::string::size_type start = 0;
224 std::string::size_type end = type_names.find_first_of(',');
225 while (end != std::string::npos) {
226 types->push_back(StringToType(type_names.substr(start, end)));
227 // Skip ',' to find the next element.
228 start = end + 1;
229 end = type_names.find_first_of(',', start);
230 }
231 if (start >= type_names.size()) {
232 return false;
233 }
234 types->push_back(StringToType(type_names.substr(start)));
235 return true;
236 }
237
TensorStrToType(const std::string & type_name)238 TypePtr TensorStrToType(const std::string &type_name) {
239 TypePtr type = nullptr;
240 if (type_name == "Tensor") {
241 type = std::make_shared<TensorType>();
242 } else {
243 auto start = type_name.find_first_of('[') + 1;
244 auto end = type_name.find_last_of(']');
245 if (start >= type_name.size()) {
246 return nullptr;
247 }
248 auto element_str = type_name.substr(start, end - start);
249 auto element_type = StringToType(element_str);
250 if (element_type == nullptr) {
251 return nullptr;
252 }
253 type = std::make_shared<TensorType>(element_type);
254 }
255 return type;
256 }
257
RowTensorStrToType(const std::string & type_name)258 TypePtr RowTensorStrToType(const std::string &type_name) {
259 if (type_name == "RowTensor") {
260 return std::make_shared<RowTensorType>();
261 }
262 auto start = type_name.find_first_of('[') + 1;
263 auto end = type_name.find_last_of(']');
264 if (start >= type_name.size()) {
265 return nullptr;
266 }
267 auto element_str = type_name.substr(start, end - start);
268 auto element_type = StringToType(element_str);
269 if (element_type == nullptr) {
270 return nullptr;
271 }
272 return std::make_shared<RowTensorType>(element_type);
273 }
274
COOTensorStrToType(const std::string & type_name)275 TypePtr COOTensorStrToType(const std::string &type_name) {
276 TypePtr type = nullptr;
277 if (type_name == "COOTensor") {
278 type = std::make_shared<COOTensorType>();
279 } else {
280 size_t start = type_name.find_first_of('[');
281 size_t end = type_name.find_last_of(']');
282 // It's better to using regular expression, now just do simple check.
283 if (start == std::string::npos || end == std::string::npos || end < start) {
284 MS_EXCEPTION(NotSupportError) << "Expect format like 'COOTensor[type1, type2, ...]', but got '" << type_name
285 << "' that not provide pair of ('[', ']').";
286 }
287 start = start + 1;
288 std::string element_strs = type_name.substr(start, end - start);
289 std::vector<TypePtr> element_types;
290 auto ret = StringToVectorOfType(element_strs, &element_types);
291 if (!ret) {
292 MS_EXCEPTION(NotSupportError) << "Expect format like 'COOTensor[type1, type2, ...]', but got '" << type_name
293 << "' that miss typename after ','.";
294 }
295 type = std::make_shared<COOTensorType>(element_types);
296 }
297 return type;
298 }
299
CSRTensorStrToType(const std::string & type_name)300 TypePtr CSRTensorStrToType(const std::string &type_name) {
301 TypePtr type = nullptr;
302 if (type_name == "CSRTensor") {
303 type = std::make_shared<CSRTensorType>();
304 } else {
305 size_t start = type_name.find_first_of('[');
306 size_t end = type_name.find_last_of(']');
307 // It's better to using regular expression, now just do simple check.
308 if (start == std::string::npos || end == std::string::npos || end < start) {
309 MS_EXCEPTION(NotSupportError) << "Expect format like 'CSRTensor[type1, type2, ...]', but got '" << type_name
310 << "' that not provide pair of ('[', ']').";
311 }
312 start = start + 1;
313 std::string element_strs = type_name.substr(start, end - start);
314 std::vector<TypePtr> element_types;
315 auto ret = StringToVectorOfType(element_strs, &element_types);
316 if (!ret) {
317 MS_EXCEPTION(NotSupportError) << "Expect format like 'CSRTensor[type1, type2, ...]', but got '" << type_name
318 << "' that miss typename after ','.";
319 }
320 type = std::make_shared<CSRTensorType>(element_types);
321 }
322 return type;
323 }
324
MapTensorStrToType(const std::string & type_name)325 TypePtr MapTensorStrToType(const std::string &type_name) {
326 if (type_name == "MapTensor") {
327 return std::make_shared<MapTensorType>();
328 }
329 size_t start = type_name.find_first_of('[');
330 size_t end = type_name.find_last_of(']');
331 // It's better to using regular expression, now just do simple check.
332 if (start == std::string::npos || end == std::string::npos || end < start) {
333 MS_EXCEPTION(NotSupportError) << "Expect format like 'MapTensor[key_dtype, value_dtype]', but got '" << type_name
334 << "' that not provide pair of ('[', ']').";
335 }
336 start = start + 1;
337 std::string element_strs = type_name.substr(start, end - start);
338 std::vector<TypePtr> element_types;
339 auto ret = StringToVectorOfType(element_strs, &element_types);
340 constexpr size_t num_of_elements = 2;
341 if (!ret || element_types.size() != num_of_elements) {
342 MS_EXCEPTION(NotSupportError) << "Expect format like 'MapTensor[key_dtype, value_dtype]', but got '" << type_name
343 << "' that miss typename after ','.";
344 }
345 return std::make_shared<MapTensorType>(element_types[0], element_types[1]);
346 }
347
UndeterminedStrToType(const std::string & type_name)348 TypePtr UndeterminedStrToType(const std::string &type_name) {
349 if (type_name == "Undetermined") {
350 return std::make_shared<UndeterminedType>();
351 }
352 auto start = type_name.find_first_of('[') + 1;
353 auto end = type_name.find_last_of(']');
354 if (start >= type_name.size()) {
355 return nullptr;
356 }
357 auto element_str = type_name.substr(start, end - start);
358 auto element_type = StringToType(element_str);
359 if (element_type == nullptr) {
360 return nullptr;
361 }
362 return std::make_shared<UndeterminedType>(element_type);
363 }
364
ListStrToType(const std::string & type_name)365 TypePtr ListStrToType(const std::string &type_name) {
366 TypePtr type = nullptr;
367 if (type_name == "List") {
368 type = std::make_shared<List>();
369 } else {
370 auto start = type_name.find_first_of('[');
371 auto end = type_name.find_last_of(']');
372 // It's better to using regular expression, now just do simple check.
373 if (start == std::string::npos || end == std::string::npos || end < start) {
374 MS_EXCEPTION(NotSupportError) << "Expect format like 'List[type1, type2, ...]', but got '" << type_name
375 << "' that not provide pair of ('[', ']').";
376 }
377 start = start + 1;
378 std::string element_strs = type_name.substr(start, end - start);
379 std::vector<TypePtr> element_types;
380 auto ret = StringToVectorOfType(element_strs, &element_types);
381 if (!ret) {
382 MS_EXCEPTION(NotSupportError) << "Expect format like 'List[type1, type2, ...]', but got '" << type_name
383 << "' that miss typename after ','.";
384 }
385 type = std::make_shared<List>(element_types);
386 }
387
388 return type;
389 }
390
TupleStrToType(const std::string & type_name)391 TypePtr TupleStrToType(const std::string &type_name) {
392 TypePtr type = nullptr;
393 if (type_name == "Tuple") {
394 type = std::make_shared<Tuple>();
395 } else {
396 size_t start = type_name.find_first_of('[');
397 size_t end = type_name.find_last_of(']');
398 // It's better to using regular expression, now just do simple check.
399 if (start == std::string::npos || end == std::string::npos || end < start) {
400 MS_EXCEPTION(NotSupportError) << "Expect format like 'Tuple[type1, type2, ...]', but got '" << type_name
401 << "' that not provide pair of ('[', ']').";
402 }
403 start = start + 1;
404 std::string element_strs = type_name.substr(start, end - start);
405 std::vector<TypePtr> element_types;
406 auto ret = StringToVectorOfType(element_strs, &element_types);
407 if (!ret) {
408 MS_EXCEPTION(NotSupportError) << "Expect format like 'Tuple[type1, type2, ...]', but got '" << type_name
409 << "' that miss typename after ','.";
410 }
411 type = std::make_shared<Tuple>(element_types);
412 }
413 return type;
414 }
415
FunctionStrToType(const std::string & type_name)416 TypePtr FunctionStrToType(const std::string &type_name) {
417 TypePtr type = nullptr;
418
419 if (type_name == "Function") {
420 type = std::make_shared<Function>();
421 } else {
422 // format: [(para1, para2, para3, ...) retval]
423 size_t start = type_name.find_first_of('[');
424 size_t end = type_name.find_last_of(']');
425 // It's better to using regular expression, now just do simple check.
426 if (start == std::string::npos || end == std::string::npos || end < start) {
427 MS_EXCEPTION(NotSupportError) << "Expect format like 'Function[(type1, type2, ...), ret_type]', but got '"
428 << type_name << "' that not provide pair of ('[', ']').";
429 }
430 start = start + 1;
431 std::string str_all = type_name.substr(start, end - start);
432 size_t start_a = str_all.find_first_of('(');
433 size_t end_a = str_all.find_last_of(')');
434 // It's better to using regular expression, now just do simple check.
435 if (start_a == std::string::npos || end_a == std::string::npos || end_a < start_a) {
436 MS_EXCEPTION(NotSupportError) << "Expect format like 'Function[(type1, type2, ...), ret_type]', but got '"
437 << type_name << "' that not provide pair of ('(', ')').";
438 }
439 start_a = start_a + 1;
440 std::string str_args = str_all.substr(start_a, end_a - start_a);
441 // bypass " " between ")" and retval
442 start = end_a + 2;
443 if (start >= str_all.size()) {
444 MS_EXCEPTION(NotSupportError) << "Expect format like 'Function[(type1, type2, ...), ret_type]', but got '"
445 << type_name;
446 }
447 std::string str_retval = str_all.substr(start);
448 std::vector<TypePtr> args_type;
449 auto ret = StringToVectorOfType(str_args, &args_type);
450 if (!ret) {
451 MS_EXCEPTION(NotSupportError) << "Expect format like 'Function[(type1, type2, ...), ret_type]', but got '"
452 << type_name;
453 }
454 TypePtr retval = StringToType(str_retval);
455 type = std::make_shared<Function>(args_type, retval);
456 }
457 return type;
458 }
459 } // namespace
460
GetTypeByFullString(const std::string & type_name)461 TypePtr GetTypeByFullString(const std::string &type_name) {
462 static std::map<std::string, TypePtr> type_map = {{"None", std::make_shared<TypeNone>()},
463 {"Ellipsis", std::make_shared<TypeEllipsis>()},
464 {"TypeType", std::make_shared<TypeType>()},
465 {"SymbolicKeyType", std::make_shared<SymbolicKeyType>()},
466 {"RefKeyType", std::make_shared<RefKeyType>()},
467 {"EnvType", std::make_shared<EnvType>()},
468 {"Number", std::make_shared<Number>()},
469 {"Bool", std::make_shared<Bool>()},
470 {"bool", std::make_shared<Bool>()},
471 {"Slice", std::make_shared<Slice>()},
472 {"Dictionary", std::make_shared<Dictionary>()},
473 {"String", std::make_shared<String>()},
474 {"Problem", std::make_shared<Problem>()},
475 {"mstype", std::make_shared<TypeType>()},
476 {"Keyword", std::make_shared<Keyword>()},
477 {"UMonad", kUMonadType},
478 {"IOMonad", kIOMonadType}};
479
480 auto iter = type_map.find(type_name);
481 return iter == type_map.end() ? nullptr : iter->second;
482 }
483
GetTypeByStringStarts(const std::string & type_name)484 TypePtr GetTypeByStringStarts(const std::string &type_name) {
485 struct name_cmp {
486 bool operator()(const std::string &l, const std::string &r) const {
487 auto cmp_len = std::min(l.length(), r.length());
488 return r.compare(0, cmp_len, l, 0, cmp_len) < 0;
489 }
490 };
491 static std::map<std::string, std::function<TypePtr(const std::string &)>, name_cmp> type_map = {
492 {"Int", [](const std::string &type_name) -> TypePtr { return StringToNumberType<Int>(type_name, "Int"); }},
493 {"int", [](const std::string &type_name) -> TypePtr { return StringToNumberType<Int>(type_name, "int"); }},
494 {"UInt", [](const std::string &type_name) -> TypePtr { return StringToNumberType<UInt>(type_name, "UInt"); }},
495 {"uint", [](const std::string &type_name) -> TypePtr { return StringToNumberType<UInt>(type_name, "uint"); }},
496 {"Float", [](const std::string &type_name) -> TypePtr { return StringToNumberType<Float>(type_name, "Float"); }},
497 {"float", [](const std::string &type_name) -> TypePtr { return StringToNumberType<Float>(type_name, "float"); }},
498 {"BFloat", [](const std::string &type_name) -> TypePtr { return StringToNumberType<BFloat>(type_name, "BFloat"); }},
499 {"bfloat", [](const std::string &type_name) -> TypePtr { return StringToNumberType<BFloat>(type_name, "bfloat"); }},
500 {"Complex", [](const std::string &tname) -> TypePtr { return StringToNumberType<Complex>(tname, "Complex"); }},
501 {"complex", [](const std::string &tname) -> TypePtr { return StringToNumberType<Complex>(tname, "complex"); }},
502 {"Tensor", [](const std::string &type_name) -> TypePtr { return TensorStrToType(type_name); }},
503 {"Undetermined", [](const std::string &type_name) -> TypePtr { return UndeterminedStrToType(type_name); }},
504 {"RowTensor", [](const std::string &type_name) -> TypePtr { return RowTensorStrToType(type_name); }},
505 {"COOTensor", [](const std::string &type_name) -> TypePtr { return COOTensorStrToType(type_name); }},
506 {"CSRTensor", [](const std::string &type_name) -> TypePtr { return CSRTensorStrToType(type_name); }},
507 {"MapTensor", [](const std::string &type_name) -> TypePtr { return MapTensorStrToType(type_name); }},
508 {"List", [](const std::string &type_name) -> TypePtr { return ListStrToType(type_name); }},
509 {"Tuple", [](const std::string &type_name) -> TypePtr { return TupleStrToType(type_name); }},
510 {"Function", [](const std::string &type_name) -> TypePtr { return FunctionStrToType(type_name); }}};
511 auto iter = type_map.find(type_name);
512 return iter == type_map.end() ? nullptr : iter->second(type_name);
513 }
514
StringToType(const std::string & type_name)515 TypePtr StringToType(const std::string &type_name) {
516 auto type = GetTypeByFullString(type_name);
517 if (type == nullptr) {
518 type = GetTypeByStringStarts(type_name);
519 }
520 if (type == nullptr) {
521 // - unsupported to convert
522 // Class
523 // SymbolicType
524 // JTagged
525 // Any
526 // External
527 MS_LOG(EXCEPTION) << "Unsupported type name: " << type_name << "!";
528 }
529 return type;
530 }
531
StringToTypeId(const std::string & type_name)532 TypeId StringToTypeId(const std::string &type_name) { return StringToType(type_name)->type_id(); }
533
IsIdentidityOrSubclass(TypePtr const & x,TypePtr const & base_type)534 bool IsIdentidityOrSubclass(TypePtr const &x, TypePtr const &base_type) {
535 if (x == nullptr || base_type == nullptr) {
536 MS_LOG(ERROR) << "Type is nullptr.";
537 return false;
538 }
539 auto type_id = base_type->type_id();
540 if (type_id == kTypeUnknown || x->type_id() == kTypeUnknown) {
541 return false;
542 } else if (!(base_type->IsGeneric())) {
543 return *(base_type) == *(x);
544 } else if (type_id == x->type_id() || type_id == x->generic_type_id() || type_id == x->object_type() ||
545 type_id == x->meta_type()) {
546 return true;
547 } else {
548 return false;
549 }
550 }
551
IsSubType(TypePtr const & t1,TypePtr const & t2)552 bool IsSubType(TypePtr const &t1, TypePtr const &t2) {
553 MS_EXCEPTION_IF_NULL(t1);
554 if (t1->type_id() == kTypeUnknown) {
555 return false;
556 } else if (t2 != nullptr) {
557 return IsIdentidityOrSubclass(t1, t2);
558 } else {
559 return true;
560 }
561 }
562 } // namespace mindspore
563