int32_t sp::ComputeSizeOfType(ReportingContext &cc, Type *aType, size_t level) { if (aType->isUnresolvedTypedef()) { cc.report(rmsg::recursive_type); return 0; } if (!aType->isArray()) { cc.report(rmsg::sizeof_needs_array); return 0; } ArrayType *type = aType->toArray(); for (size_t i = 1; i <= level; i++) { if (!type->contained()->isArray()) { cc.report(rmsg::sizeof_invalid_rank); return 0; } type = type->contained()->toArray(); } if (!type->hasFixedLength()) { cc.report(rmsg::sizeof_indeterminate); return 0; } return type->fixedLength(); }
bool Type::Compare(Type *left, Type *right) { if (left == right) return true; if (left->kind() != right->kind()) return false; switch (left->kind()) { case Type::PRIMITIVE: return left->primitive() == right->primitive(); case Type::ARRAY: { ArrayType *aleft = left->toArray(); ArrayType *aright = right->toArray(); if (aleft->levels() != aright->levels()) return false; if (aleft->isFixedLength() != aright->isFixedLength()) return false; if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength()) return false; return Compare(aleft->contained(), aright->contained()); } case Type::FUNCTION: { FunctionType *fleft = left->toFunction(); FunctionType *fright = right->toFunction(); if (!Compare(fleft->returnType(), fright->returnType())) return false; if (fleft->parameters()->length() != fright->parameters()->length()) return false; if (fleft->isNative() != fright->isNative()) return false; if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic())) return false; for (unsigned i = 0; i < fleft->parameters()->length(); i++) { Type *leftparam = fleft->parameterAt(i); Type *rightparam = fright->parameterAt(i); if (!Compare(leftparam, rightparam)) return false; } return true; } case Type::ENUM: return false; case Type::VOID: return true; default: assert(left->kind() == Type::REFERENCE); return Compare(left->toReference()->contained(), right->toReference()->contained()); } }
// Since const is transitive, we require it to be threaded through type // equivalence tests. bool sp::AreTypesEquivalent(Type *a, Type *b, Qualifiers context) { Qualifiers qa = (a->qualifiers() | context); Qualifiers qb = (b->qualifiers() | context); if (qa != qb) return false; a = a->canonical(); b = b->canonical(); if (a == b) return true; switch (a->canonicalKind()) { case Type::Kind::Primitive: // Either |b| is not primitive, or they should not have the same // primitive type since each type is a singleton. assert(!b->isPrimitive() || a->primitive() != b->primitive()); return false; case Type::Kind::Function: { if (!b->isFunction()) return false; // const is not transitive through function signatures. return AreFunctionTypesEqual(a->toFunction(), b->toFunction()); } case Type::Kind::Array: { if (!b->isArray()) return false; ArrayType *aa = a->toArray(); ArrayType *ba = b->toArray(); while (true) { // Both arrays must be either dynamic or have the same fixed size. if (aa->hasFixedLength() != ba->hasFixedLength()) return false; if (aa->hasFixedLength() && aa->fixedLength() != ba->fixedLength()) return false; // Both contained types must be the same type. Type *innerA = aa->contained(); Type *innerB = ba->contained(); if (innerA->isArray() != innerB->isArray()) return false; if (!innerA->isArray()) { // const is transitive through arrays. if (!AreTypesEquivalent(innerA, innerB, context)) return false; // If neither contained type is an array, we're done. break; } // Re-check qualifiers. Qualifiers qa = (innerA->qualifiers() | context); Qualifiers qb = (innerB->qualifiers() | context); if (qa != qb) return false; } return true; } // These types have unique instances. case Type::Kind::Void: case Type::Kind::Unchecked: case Type::Kind::MetaFunction: // These types are named and must have the same identity. case Type::Kind::Struct: case Type::Kind::Typeset: case Type::Kind::Enum: // Handled by a == b check earlier. return false; default: // Should not get Unresolvable, Typedef, or Qualifier here. assert(false); return false; } }