/* * TYPE.C * * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the * COPYRIGHT file at the base of the distribution. */ #include "defs.h" Type DynamicLValueType; Type DynamicRValueType; Type NumericType; /* generic numeric placeholder */ Type IntegralType; /* generic integral placeholder */ Type SIntegerType; /* generic signed integer placeholder */ Type UIntegerType; /* generic unsigned integer placeholder */ Type VoidType; Type BoolType; Type Int8Type; Type UInt8Type; Type Int16Type; Type UInt16Type; Type Int32Type; Type UInt32Type; Type Int64Type; Type UInt64Type; Type Int128Type; Type UInt128Type; Type IntPtrType; Type UIntPtrType; Type OffType; Type SizeType; Type FloatType; /* generic float placeholder */ Type Float32Type; Type Float64Type; Type Float128Type; Type PointerType; /* generic pointer placeholder */ Type CCharType; /* const char */ Type StrType; /* const char * */ Type CharPtrType; /* char * */ Type CharPtrPtrType; /* char ** */ Type VoidPtrType; /* void * */ Type VoidRefType; /* void @ */ Type CVoidPtrType; /* const void * */ Type LVoidPtrType; /* lvalue void * */ Type LexRefType; /* run-time access class tie-ins */ Type ScopeType; Type DeclarationType; Type SemGroupType; Type PointerInfoType; Type TypeType; Type FILLERTypeType; Type FILLERDeclType; typelist_t DynamicTypeList = RUNE_HEAD_INITIALIZER(DynamicTypeList); typelist_t CompoundTypeList = RUNE_HEAD_INITIALIZER(CompoundTypeList); typelist_t ArgsTypeList = RUNE_HEAD_INITIALIZER(ArgsTypeList); typelist_t StorageTypeList = RUNE_HEAD_INITIALIZER(StorageTypeList); static void initInternalClassType(Type *type, Declaration *d); Type *BaseTypeAry[] = { &DynamicLValueType, &DynamicRValueType, &NumericType, &IntegralType, &SIntegerType, &UIntegerType, &VoidType, &BoolType, &Int8Type, &UInt8Type, &Int16Type, &UInt16Type, &Int32Type, &UInt32Type, &Int64Type, &UInt64Type, &Int128Type, &UInt128Type, &IntPtrType, &UIntPtrType, &OffType, &SizeType, &FloatType, &Float32Type, &Float64Type, &Float128Type, &PointerType, &CCharType, &StrType, &CharPtrType, &CharPtrPtrType, &VoidPtrType, &VoidRefType, &CVoidPtrType, &LVoidPtrType, &LexRefType, &ScopeType, &DeclarationType, &SemGroupType, &PointerInfoType, &TypeType, &FILLERTypeType, &FILLERDeclType, NULL }; void initType(Type *type, typelist_t *list, int op) { type->ty_Op = op; RUNE_INIT(&type->ty_QList); if (list) RUNE_INSERT_TAIL(list, type, ty_Node); type->ty_SQList = list; type->ty_Info.in_Type = type; type->ty_Info.in_Refs = PINFO_STATIC; } void initQualType(Type *type, typelist_t *list, int op, int sqflags) { initType(type, list, op); type->ty_SQFlags = sqflags; } void initPtrType(Type *type, Type *ptrto, int sqflags) { initQualType(type, &ptrto->ty_QList, TY_PTRTO, sqflags); type->ty_PtrType.et_Type = ptrto; /*type->ty_Bytes = sizeof(PointerStor);*/ type->ty_AlignMask = POINTERSTOR_ALIGN; } void initCPtrType(Type *type, Type *ptrto, int sqflags) { initQualType(type, &ptrto->ty_QList, TY_CPTRTO, sqflags); type->ty_PtrType.et_Type = ptrto; /*type->ty_Bytes = sizeof(void *);*/ type->ty_AlignMask = sizeof(void *) - 1; } static void initRefType(Type *type, Type *refto, int sqflags) { initQualType(type, &refto->ty_QList, TY_REFTO, sqflags); type->ty_RefType.et_Type = refto; /*type->ty_Bytes = sizeof(PointerStor);*/ type->ty_AlignMask = POINTERSTOR_ALIGN; } void TypeInit(void) { int i; initQualType(&DynamicLValueType, &DynamicTypeList, TY_DYNAMIC, SF_LVALUE); initType(&DynamicRValueType, &DynamicTypeList, TY_DYNAMIC); initType(&NumericType, NULL, TY_UNRESOLVED); initType(&IntegralType, NULL, TY_UNRESOLVED); initType(&SIntegerType, NULL, TY_UNRESOLVED); initType(&UIntegerType, NULL, TY_UNRESOLVED); initType(&FloatType, NULL, TY_UNRESOLVED); initType(&PointerType, NULL, TY_UNRESOLVED); PointerType.ty_AlignMask = POINTERSTOR_ALIGN; initType(&VoidType, NULL, TY_UNRESOLVED); initType(&BoolType, NULL, TY_UNRESOLVED); initType(&Int8Type, NULL, TY_UNRESOLVED); initType(&UInt8Type, NULL, TY_UNRESOLVED); initType(&Int16Type, NULL, TY_UNRESOLVED); initType(&UInt16Type, NULL, TY_UNRESOLVED); initType(&Int32Type, NULL, TY_UNRESOLVED); initType(&UInt32Type, NULL, TY_UNRESOLVED); initType(&Int64Type, NULL, TY_UNRESOLVED); initType(&UInt64Type, NULL, TY_UNRESOLVED); initType(&IntPtrType, NULL, TY_UNRESOLVED); initType(&UIntPtrType, NULL, TY_UNRESOLVED); initType(&OffType, NULL, TY_UNRESOLVED); initType(&SizeType, NULL, TY_UNRESOLVED); initType(&Float32Type, NULL, TY_UNRESOLVED); initType(&Float64Type, NULL, TY_UNRESOLVED); initType(&Float128Type, NULL, TY_UNRESOLVED); initQualType(&CCharType, NULL, TY_UNRESOLVED, SF_CONST); initPtrType(&StrType, &CCharType, 0); initPtrType(&CharPtrType, &UInt8Type, 0); initPtrType(&CharPtrPtrType, &CharPtrType, 0); initPtrType(&VoidPtrType, &VoidType, 0); initRefType(&VoidRefType, &VoidType, 0); initCPtrType(&CVoidPtrType, &VoidType, SF_CONST); initPtrType(&LVoidPtrType, &VoidType, SF_LVALUE); /* * Mark internal types (not all are bound to classes so it is * easiest to just do it here). This will prevent the collapse * code from trying to collapse our base types. */ for (i = 0; BaseTypeAry[i]; ++i) BaseTypeAry[i]->ty_Flags |= TF_ISINTERNAL; StrTableAlloc("void", 4, SPECIAL_INTERNAL_VOID); StrTableAlloc("bool", 4, SPECIAL_INTERNAL_BOOL); StrTableAlloc("int8_t", 6, SPECIAL_INTERNAL_INT8); StrTableAlloc("uint8_t", 7, SPECIAL_INTERNAL_UINT8); StrTableAlloc("int16_t", 7, SPECIAL_INTERNAL_INT16); StrTableAlloc("uint16_t", 8, SPECIAL_INTERNAL_UINT16); StrTableAlloc("int32_t", 7, SPECIAL_INTERNAL_INT32); StrTableAlloc("uint32_t", 8, SPECIAL_INTERNAL_UINT32); StrTableAlloc("int64_t", 7, SPECIAL_INTERNAL_INT64); StrTableAlloc("uint64_t", 8, SPECIAL_INTERNAL_UINT64); StrTableAlloc("int128_t", 8, SPECIAL_INTERNAL_INT128); StrTableAlloc("uint128_t", 9, SPECIAL_INTERNAL_UINT128); StrTableAlloc("float32_t", 9, SPECIAL_INTERNAL_FLOAT32); StrTableAlloc("float64_t", 9, SPECIAL_INTERNAL_FLOAT64); StrTableAlloc("float128_t", 10, SPECIAL_INTERNAL_FLOAT128); StrTableAlloc("intptr_t", 8, SPECIAL_INTERNAL_INTPTR); StrTableAlloc("uintptr_t", 9, SPECIAL_INTERNAL_UINTPTR); StrTableAlloc("size_t", 6, SPECIAL_INTERNAL_SIZE); StrTableAlloc("off_t", 5, SPECIAL_INTERNAL_OFF); StrTableAlloc("Float", 5, SPECIAL_INTERNAL_FLOAT); StrTableAlloc("Pointer", 7, SPECIAL_INTERNAL_POINTER); StrTableAlloc("Numeric", 7, SPECIAL_INTERNAL_NUMERIC); StrTableAlloc("Integral", 8, SPECIAL_INTERNAL_INTEGRAL); StrTableAlloc("SInteger", 8, SPECIAL_INTERNAL_SINTEGER); StrTableAlloc("UInteger", 8, SPECIAL_INTERNAL_UINTEGER); StrTableAlloc("LexRef", 6, SPECIAL_INTERNAL_LEXREF); StrTableAlloc("Scope", 5, SPECIAL_INTERNAL_SCOPE); StrTableAlloc("Declaration", 11, SPECIAL_INTERNAL_DECLARATION); StrTableAlloc("SemGroup", 8, SPECIAL_INTERNAL_SEMGROUP); StrTableAlloc("PointerInfo", 11, SPECIAL_INTERNAL_POINTERINFO); StrTableAlloc("Type", 4, SPECIAL_INTERNAL_TYPE); StrTableAlloc("FILLERType", 10, SPECIAL_INTERNAL_FILLERTYPE); StrTableAlloc("FILLERDecl", 10, SPECIAL_INTERNAL_FILLERDECL); StrTableAlloc("__count", 7, SPECIAL_COUNT); StrTableAlloc("__data", 6, SPECIAL_DATA); StrTableAlloc("__varcount", 10, SPECIAL_VAR_COUNT); StrTableAlloc("__vardata", 9, SPECIAL_VAR_DATA); StrTableAlloc("__typeid", 8, SPECIAL_TYPEID); StrTableAlloc("__typestr", 9, SPECIAL_TYPESTR); StrTableAlloc("NULL", 4, SPECIAL_NULL); } /* * Attach an internal class, creating a global summary type for it that * allows our interpreter and code generator to make various assumptions. */ int InternalClassAttach(Parse *p __unused, int t, Declaration *d) { Type *itype = NULL; int s; dassert_decl(d, d->d_Op == DOP_CLASS); if ((s = StrTableSpecial(d->d_Id)) & SPECIALF_INTERNAL) { switch(s) { case SPECIAL_INTERNAL_VOID: itype = &VoidType; break; case SPECIAL_INTERNAL_BOOL: /* * Special flag helper (resolver sets TF_ISBOOL in * in the type) */ itype = &BoolType; d->d_ClassDecl.ed_SemGroup->sg_Flags |= SGF_ISBOOL; break; case SPECIAL_INTERNAL_INT8: itype = &Int8Type; break; case SPECIAL_INTERNAL_UINT8: itype = &UInt8Type; break; case SPECIAL_INTERNAL_INT16: itype = &Int16Type; break; case SPECIAL_INTERNAL_UINT16: itype = &UInt16Type; break; case SPECIAL_INTERNAL_INT32: itype = &Int32Type; break; case SPECIAL_INTERNAL_UINT32: itype = &UInt32Type; break; case SPECIAL_INTERNAL_INT64: itype = &Int64Type; break; case SPECIAL_INTERNAL_UINT64: itype = &UInt64Type; break; case SPECIAL_INTERNAL_INT128: itype = &Int128Type; break; case SPECIAL_INTERNAL_UINT128: itype = &UInt128Type; break; case SPECIAL_INTERNAL_FLOAT: /* * Special flag helper (resolver sets TF_ISFLOATING in * in the type) */ itype = &FloatType; d->d_ClassDecl.ed_SemGroup->sg_Flags |= SGF_ISFLOATING; break; case SPECIAL_INTERNAL_FLOAT32: itype = &Float32Type; break; case SPECIAL_INTERNAL_FLOAT64: itype = &Float64Type; break; case SPECIAL_INTERNAL_FLOAT128: itype = &Float128Type; break; case SPECIAL_INTERNAL_INTPTR: itype = &IntPtrType; break; case SPECIAL_INTERNAL_UINTPTR: itype = &UIntPtrType; break; case SPECIAL_INTERNAL_OFF: itype = &OffType; break; case SPECIAL_INTERNAL_SIZE: itype = &SizeType; break; /* NOTE: There is no ssize_t in rune. size_t is signed */ case SPECIAL_INTERNAL_POINTER: itype = &PointerType; break; case SPECIAL_INTERNAL_NUMERIC: itype = &NumericType; break; case SPECIAL_INTERNAL_INTEGRAL: itype = &IntegralType; break; case SPECIAL_INTERNAL_SINTEGER: /* * Special flag helper (resolver sets TF_ISINTEGER in * in the type) */ itype = &SIntegerType; d->d_ClassDecl.ed_SemGroup->sg_Flags |= SGF_ISINTEGER; break; case SPECIAL_INTERNAL_UINTEGER: /* * Special flag helper (resolver sets TF_ISINTEGER * and TF_ISUNSIGNED in the type) */ itype = &UIntegerType; d->d_ClassDecl.ed_SemGroup->sg_Flags |= SGF_ISUNSIGNED; d->d_ClassDecl.ed_SemGroup->sg_Flags |= SGF_ISINTEGER; break; case SPECIAL_INTERNAL_LEXREF: itype = &LexRefType; break; case SPECIAL_INTERNAL_SCOPE: itype = &ScopeType; break; case SPECIAL_INTERNAL_DECLARATION: itype = &DeclarationType; break; case SPECIAL_INTERNAL_SEMGROUP: itype = &SemGroupType; break; case SPECIAL_INTERNAL_POINTERINFO: itype = &PointerInfoType; break; case SPECIAL_INTERNAL_TYPE: itype = &TypeType; break; case SPECIAL_INTERNAL_FILLERTYPE: itype = &FILLERTypeType; break; case SPECIAL_INTERNAL_FILLERDECL: itype = &FILLERDeclType; break; default: dpanic("Unknown internal class: %s", d->d_Id); break; } } initInternalClassType(itype, d); /* * Fixup for const int8 pointers... we did not have * a QList to put CCharType on until now. It will * wind up on the SemGroup's sg_ClassList. */ if (itype == &UInt8Type) { TypeToQualType(itype, &CCharType, itype->ty_SQFlags | SF_CONST, NULL); } return(t); } /* * This is mostly deprecated except for official type aliases such as * intptr_t. */ int InternalTypeAttach(Parse *p, int t, Declaration *d) { Type *itype = NULL; int s; dassert_decl(d, d->d_Op == DOP_TYPEDEF); if ((s = StrTableSpecial(d->d_Id)) & SPECIALF_INTERNAL) { switch(s) { case SPECIAL_INTERNAL_VOID: itype = &VoidType; break; case SPECIAL_INTERNAL_BOOL: itype = &BoolType; break; case SPECIAL_INTERNAL_INT8: itype = &Int8Type; break; case SPECIAL_INTERNAL_UINT8: itype = &UInt8Type; break; case SPECIAL_INTERNAL_INT16: itype = &Int16Type; break; case SPECIAL_INTERNAL_UINT16: itype = &UInt16Type; break; case SPECIAL_INTERNAL_INT32: itype = &Int32Type; break; case SPECIAL_INTERNAL_UINT32: itype = &UInt32Type; break; case SPECIAL_INTERNAL_INT64: itype = &Int64Type; break; case SPECIAL_INTERNAL_UINT64: itype = &UInt64Type; break; case SPECIAL_INTERNAL_FLOAT32: itype = &Float32Type; break; case SPECIAL_INTERNAL_FLOAT64: itype = &Float64Type; break; case SPECIAL_INTERNAL_FLOAT128: itype = &Float128Type; break; case SPECIAL_INTERNAL_INTPTR: itype = &IntPtrType; break; case SPECIAL_INTERNAL_UINTPTR: itype = &UIntPtrType; break; case SPECIAL_INTERNAL_OFF: itype = &OffType; break; case SPECIAL_INTERNAL_SIZE: itype = &SizeType; break; /* NOTE: There is no ssize_t in rune. size_t is signed */ case SPECIAL_INTERNAL_POINTER: itype = &PointerType; break; case SPECIAL_INTERNAL_NUMERIC: itype = &NumericType; break; case SPECIAL_INTERNAL_INTEGRAL: itype = &IntegralType; break; case SPECIAL_INTERNAL_SINTEGER: itype = &SIntegerType; break; case SPECIAL_INTERNAL_UINTEGER: itype = &UIntegerType; break; default: itype = InternalRegisteredTypeLookup(d->d_Id); if (itype == NULL) dpanic("Unknown internal type: %s", d->d_Id); break; } } if (itype) { if (itype->ty_Op != TY_UNRESOLVED) { t = LexError(&p->p_Token, TOK_ERR_DUPLICATE_ATTACH); } else { Type *ntype = d->d_TypedefDecl.ed_Type; TypeToQualType(ntype, itype, ntype->ty_SQFlags, NULL); } } else { t = LexError(&p->p_Token, TOK_ERR_UNRECOGNIZED_ATTACH); } return(t); } Type * AllocType(typelist_t *list, int op) { Type *type = zalloc(sizeof(Type)); initType(type, list, op); return(type); } /* * May be used to generate a varargs compound type, in which case the * semgroup may already be resolved. * * We do no matching/caching at this time and callers assume that (for * making adjustments) to the underlying sg at parse-time via * TypeToProcType() */ Type * AllocCompoundType(SemGroup *sg) { Type *type; type = AllocType(&CompoundTypeList, TY_COMPOUND); type->ty_CompType.et_SemGroup = sg; dassert((sg->sg_Flags & SGF_RESOLVED) == 0); return(type); } /* * XXX match the compound type(s) */ Type * AllocArgsType(SemGroup *sg) { Type *type; type = AllocType(&ArgsTypeList, TY_ARGS); type->ty_ArgsType.et_SemGroup = sg; return(type); } Type * AllocStorageType(runesize_t bytes) { Type *type; RUNE_FOREACH(type, &StorageTypeList, ty_Node) { if (type->ty_Op == TY_STORAGE && type->ty_StorType.et_Bytes == bytes ) { return(type); } } type = AllocType(&StorageTypeList, TY_STORAGE); type->ty_StorType.et_Bytes = bytes; return(type); } Type * AllocUnresolvedType(SemGroup *isg, SemGroup *sg, string_t *ary, int eatAry) { Type *type = NULL; dassert_semgrp(sg, ary != NULL); RUNE_FOREACH(type, &sg->sg_ClassList, ty_Node) { int i; if (type->ty_Op != TY_UNRESOLVED) continue; if (type->ty_UnresType.et_ImportSemGroup != isg) continue; for (i = 0; ary[i]; ++i) { if (ary[i] != type->ty_UnresType.et_DottedId[i]) break; } if (ary[i] == NULL && type->ty_UnresType.et_DottedId[i] == NULL) { if (eatAry) FreeDotIdAry(ary); return(type); } } type = AllocType((sg ? &sg->sg_ClassList : NULL), TY_UNRESOLVED); type->ty_UnresType.et_DottedId = ary; type->ty_UnresType.et_SemGroup = sg; /* may be NULL */ type->ty_UnresType.et_ImportSemGroup = isg; /* may be NULL */ return(type); } /* * AllocClassType() - allocate a type representing a the semgroup which * in turn represents (typically) a class. */ Type * AllocClassType(typelist_t *list, Type *super, SemGroup *sg, int visibility) { Type *type; dassert(sg != NULL); list = &sg->sg_ClassList; RUNE_FOREACH(type, list, ty_Node) { if (type->ty_Op == TY_CLASS && type->ty_ClassType.et_SemGroup == sg && type->ty_ClassType.et_Super == super && type->ty_Visibility == visibility ) { return(type); } } if (sg) dassert(&sg->sg_ClassList == list); type = AllocType(list, TY_CLASS); type->ty_ClassType.et_SemGroup = sg; type->ty_ClassType.et_Super = super; type->ty_Visibility = visibility; return(type); } static void initInternalClassType(Type *type, Declaration *d) { SemGroup *sg = d->d_ClassDecl.ed_SemGroup; initType(type, &sg->sg_ClassList, TY_CLASS); RUNE_REMOVE(&sg->sg_ClassList, type, ty_Node); RUNE_INSERT_HEAD(&sg->sg_ClassList, type, ty_Node); type->ty_ClassType.et_SemGroup = d->d_ClassDecl.ed_SemGroup; type->ty_ClassType.et_Super = d->d_ClassDecl.ed_Super; type->ty_Visibility = d->d_ScopeFlags & SCOPE_ALL_VISIBLE; type->ty_Flags |= TF_ISINTERNAL; } Type * AllocImportType(typelist_t *list, SemGroup *sg, int visibility) { Type *type = AllocType(list, TY_IMPORT); type->ty_ImportType.et_SemGroup = sg; type->ty_Visibility = visibility; return(type); } /* * adjtype must be moved to type's QList because type is being modified * such that that is where it is expected to be. */ Type * TypeAdjustQList(Type *type, Type *adjtype) { if (adjtype) { if (adjtype->ty_SQList) RUNE_REMOVE(adjtype->ty_SQList, adjtype, ty_Node); adjtype->ty_SQList = &type->ty_QList; RUNE_INSERT_TAIL(adjtype->ty_SQList, adjtype, ty_Node); } return type; } /* * Compound types inherit locking modes if not specifically * overridden. */ Type * TypeFixupInheritedFlags(Type *type, int rqflags) { SemGroup *sg; Declaration *d; if (type->ty_Op != TY_COMPOUND) return type; /* * Assume no matching collapse yet */ sg = type->ty_CompType.et_SemGroup; RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) { if (d->d_Op != DOP_GROUP_STORAGE) continue; if ((d->d_ScopeFlags & SCOPE_LOCKING_MASK) == 0) { if (rqflags & SF_UNTRACKED) d->d_ScopeFlags |= SCOPE_UNTRACKED; if (rqflags & SF_UNLOCKED) d->d_ScopeFlags |= SCOPE_UNLOCKED; if (rqflags & SF_SOFT) d->d_ScopeFlags |= SCOPE_SOFT; if (rqflags & SF_HARD) d->d_ScopeFlags |= SCOPE_HARD; } } return type; } Type * TypeToQualType(Type *otype, Type *ntype, int sqFlags, Exp *exp) { SemGroup *sg; /* * Combine with existing qualifiers, Shortcut if no changes made. */ if (ntype == NULL && sqFlags == otype->ty_SQFlags && (exp == NULL || exp == otype->ty_AssExp) ) { return(otype); } /* * See if we already have a matching qualified type (only if storage * for the new type is not being provided). Note: the provided storage * has already been initType()d */ if (ntype == NULL) { RUNE_FOREACH(ntype, otype->ty_SQList, ty_Node) { if (ntype->ty_Op == otype->ty_Op && ntype->ty_SQFlags == sqFlags && (exp == NULL || ntype->ty_AssExp == exp) ) { if (SameType(ntype, otype, sqFlags)) return(ntype); } } } /* * Build a new qualified type and set its qualifiers, then duplicate * appropriate sections of the old type. * * Default to the same SQList as otype. */ if (ntype == NULL) { ntype = AllocType(otype->ty_SQList, otype->ty_Op); } else { if (ntype->ty_SQList) RUNE_REMOVE(ntype->ty_SQList, ntype, ty_Node); ntype->ty_SQList = otype->ty_SQList; RUNE_INSERT_TAIL(ntype->ty_SQList, ntype, ty_Node); } /* * Set the op and the expression. Unlike SQFlags, if exp is passed as * NULL we inherit the old type's default. * * The DupExp() call here is special, see DupExp()'s handling of * ex_Decl. * * Normally DupExp() is called during resolution prior to ex_Decl * being set. This is the one case where it may be called with * ex_Decl already set. * * WARNING! We do not try to resolve the type here. Various resolve * related flags in ty_Flags will be resolved later. This * includes TF_ISUNSIGNED and other TF_* flags. */ ntype->ty_Op = otype->ty_Op; if (exp) ntype->ty_AssExp = exp; else if (otype->ty_AssExp) ntype->ty_AssExp = SetDupExp(NULL, otype->ty_AssExp); ntype->ty_SQFlags = sqFlags; ntype->ty_Visibility = otype->ty_Visibility; switch(otype->ty_Op) { case TY_CLASS: /* * When updating the class, alternative forms are collapsed * into it's SemGroup->sg_ClassList and not into some * potentially long recursive chain based on ty_QList. */ sg = otype->ty_ClassType.et_SemGroup; dassert(ntype->ty_SQList == &sg->sg_ClassList); if (ntype->ty_ClassType.et_SemGroup != sg) { ntype->ty_ClassType.et_SemGroup = sg; } ntype->ty_ClassType.et_Super = otype->ty_ClassType.et_Super; break; case TY_IMPORT: ntype->ty_Visibility = otype->ty_Visibility; ntype->ty_ImportType.et_SemGroup = otype->ty_ImportType.et_SemGroup; break; case TY_CPTRTO: ntype->ty_CPtrType.et_Type = otype->ty_CPtrType.et_Type; break; case TY_PTRTO: ntype->ty_PtrType.et_Type = otype->ty_PtrType.et_Type; break; case TY_REFTO: ntype->ty_RefType.et_Type = otype->ty_RefType.et_Type; break; case TY_ARYOF: /* * note: multiple type structures may share the same array size * expression in simple qualified-type cases. YYY XXX bad bad. */ ntype->ty_AryType.et_Type = otype->ty_AryType.et_Type; ntype->ty_AryType.et_ArySize = otype->ty_AryType.et_ArySize; ntype->ty_AryType.et_SemGroup = otype->ty_AryType.et_SemGroup; ntype->ty_AryType.et_Count = otype->ty_AryType.et_Count; break; case TY_COMPOUND: ntype->ty_CompType.et_SemGroup = otype->ty_CompType.et_SemGroup; break; case TY_VAR: ntype->ty_VarType.et_Type = otype->ty_VarType.et_Type; ntype->ty_VarType.et_SemGroup = otype->ty_VarType.et_SemGroup; break; case TY_ARGS: ntype->ty_ArgsType.et_SemGroup = otype->ty_ArgsType.et_SemGroup; break; case TY_PROC: ntype->ty_ProcType.et_ArgsType = otype->ty_ProcType.et_ArgsType; ntype->ty_ProcType.et_RetType = otype->ty_ProcType.et_RetType; ntype->ty_ProcType.et_ArgCount = otype->ty_ProcType.et_ArgCount; dassert(ntype->ty_SQList == &otype->ty_ProcType.et_RetType->ty_QList); break; case TY_STORAGE: ntype->ty_StorType.et_Bytes = otype->ty_StorType.et_Bytes; break; case TY_DYNAMIC: /* * It is not legal to qualify a dynamic type other then to * add or remove SF_LVALUE. */ dpanic("Dynamic type cannot be qualified"); break; case TY_UNRESOLVED: ntype->ty_UnresType.et_DottedId = otype->ty_UnresType.et_DottedId; ntype->ty_UnresType.et_SemGroup = otype->ty_UnresType.et_SemGroup; ntype->ty_UnresType.et_ImportSemGroup = otype->ty_UnresType.et_ImportSemGroup; break; default: dassert_type(otype, 0); } return(ntype); } /* * Convert a return-type + argument-type into a procedure type. If * adjret is non-zero the return-type is converted to locked storage * (which is generally what we want). * * Match the procedure type(s) (after adjustment?) */ Type * TypeToProcType(Type *rtype, Type *atype, int adjret) { Type *type; runesize_t count = 0; Declaration *d; SemGroup *sg; dassert_type(atype, atype->ty_Op == TY_ARGS); if (adjret) rtype = TypeFixupInheritedFlags(rtype, rtype->ty_SQFlags); sg = atype->ty_CompType.et_SemGroup; RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) { ++count; } RUNE_FOREACH(type, &rtype->ty_QList, ty_Node) { if (type->ty_Op == TY_PROC) { if (type->ty_ProcType.et_ArgsType == atype && type->ty_ProcType.et_RetType == rtype && type->ty_ProcType.et_ArgCount == count ) { return(type); } } } type = AllocType(&rtype->ty_QList, TY_PROC); type->ty_ProcType.et_ArgsType = AllocArgsType(sg); type->ty_ProcType.et_RetType = rtype; type->ty_ProcType.et_ArgCount = count; return(type); } /* * Convert type to pointer-to-type */ Type * TypeToPtrType(Type *otype) { Type *type; RUNE_FOREACH(type, &otype->ty_QList, ty_Node) { if (type->ty_Op == TY_PTRTO) return(type); } type = AllocType(&otype->ty_QList, TY_PTRTO); type->ty_PtrType.et_Type = otype; return(type); } /* * Convert type to pointer-to-type */ Type * TypeToCPtrType(Type *otype) { Type *type; RUNE_FOREACH(type, &otype->ty_QList, ty_Node) { if (type->ty_Op == TY_CPTRTO) return(type); } type = AllocType(&otype->ty_QList, TY_CPTRTO); type->ty_CPtrType.et_Type = otype; return(type); } /* * Convert type to ref-to-type * * A reference type is similar to a pointer type except that the * resolver is not able to entirely know what it is pointing to. * The reference type is a superclass, but the actual type is * stored in the run-time structure. */ Type * TypeToRefType(Type *otype) { Type *type; RUNE_FOREACH(type, &otype->ty_QList, ty_Node) { if (type->ty_Op == TY_REFTO) return(type); } type = AllocType(&otype->ty_QList, TY_REFTO); type->ty_RefType.et_Type = otype; return(type); } Type * TypeToAryType(Type *otype, Exp *exp, SemGroup *sg) { Type *type; /* * XXX handle constant expression optimization for QList * XXX handle qualifiers */ type = AllocType(&otype->ty_QList, TY_ARYOF); type->ty_AryType.et_ArySize = exp; type->ty_AryType.et_Type = DelTypeQual(otype, SF_MASK_ARY_INHERIT); type->ty_AryType.et_SemGroup = sg; type->ty_SQFlags |= otype->ty_SQFlags & SF_MASK_ARY_INHERIT; return(type); } #if 0 Type * TypeToRunTimeAryType(Type *otype, int count) { Type *type; Type *t2 = DelTypeQual(otype, SF_MASK_ARY_INHERIT); RUNE_FOREACH(type, &otype->ty_QList, ty_Node) { if (type->ty_Op == TY_ARYOF && type->ty_AryType.et_Type == t2 && type->ty_AryType.et_Count == count && type->ty_SQFlags == (otype->ty_SQFlags & SF_MASK_ARY_INHERIT) ) { return(type); } } type = AllocType(&otype->ty_QList, TY_ARYOF); type->ty_AryType.et_Count = count; type->ty_AryType.et_Type = t2; type->ty_SQFlags |= otype->ty_SQFlags & SF_MASK_ARY_INHERIT; return(type); } #endif Type * TypeToVarType(Type *otype, SemGroup *sg) { Type *type; /*dassert(sg->sg_Flags & SGF_RESOLVED);*/ /*dassert(otype->ty_Flags & TF_RESOLVED);*/ RUNE_FOREACH(type, &otype->ty_QList, ty_Node) { if (type->ty_Op == TY_VAR && type->ty_VarType.et_Type == otype && type->ty_VarType.et_SemGroup == sg ) { puts("SG2"); /* YYY */ return(type); } } type = AllocType(&otype->ty_QList, TY_VAR); type->ty_VarType.et_Type = otype; type->ty_VarType.et_SemGroup = sg; #if 0 /* XXX doesn't work for var-args */ if (sg->sg_Flags & SGF_RESOLVED) { type->ty_Flags |= TF_RESOLVED; type->ty_Bytes = sg->sg_Bytes; type->ty_AlignMask = sg->sg_AlignMask; } #endif return(type); } /* * ChangeType() - given pointer, C pointer, or array of something, * return 'op' of something instead. */ Type * ChangeType(Type *type, int op) { switch(type->ty_Op) { case TY_PTRTO: switch(op) { case TY_CPTRTO: type = TypeToCPtrType(type->ty_PtrType.et_Type); break; case TY_ARYOF: type = TypeToAryType(type->ty_PtrType.et_Type, NULL, NULL); break; default: dpanic("Illegal type convesion (A)"); } break; case TY_CPTRTO: switch(op) { case TY_PTRTO: type = TypeToPtrType(type->ty_CPtrType.et_Type); break; case TY_ARYOF: type = TypeToAryType(type->ty_CPtrType.et_Type, NULL, NULL); break; default: dpanic("Illegal type convesion (B)"); } break; case TY_ARYOF: switch(op) { case TY_PTRTO: type = TypeToPtrType(type->ty_AryType.et_Type); break; case TY_CPTRTO: type = TypeToCPtrType(type->ty_AryType.et_Type); break; default: dpanic("Illegal type convesion (C)"); } break; default: dpanic("Illegal type convesion (D)"); } return(type); } /* * BaseType() - return base type * * Traverse the type to locate the base type. Store the base type * in *ptype and return the SemGroup, or return NULL if the base type * does not have a SemGroup. */ SemGroup * BaseType(Type **ptype) { Type *type = *ptype; for (;;) { switch(type->ty_Op) { case TY_CPTRTO: type = type->ty_CPtrType.et_Type; continue; case TY_PTRTO: type = type->ty_PtrType.et_Type; continue; case TY_REFTO: type = type->ty_RefType.et_Type; continue; case TY_ARYOF: type = type->ty_AryType.et_Type; continue; } break; } *ptype = type; switch(type->ty_Op) { case TY_CLASS: return(type->ty_ClassType.et_SemGroup); case TY_COMPOUND: return(type->ty_CompType.et_SemGroup); case TY_ARGS: return(type->ty_ArgsType.et_SemGroup); case TY_PROC: case TY_VAR: case TY_DYNAMIC: case TY_STORAGE: return(NULL); case TY_UNRESOLVED: default: dassert_type(type, 0); return(NULL); /* avoid compiler complaints */ } } /* * DupType() - create a duplicate of a type, possibly in a new SemGroup. * * This code is used when duplicating procedures and other elements * when merging a superclass into a subclass. * * If sg is NULL, stype is simply returned. The case is used when we * try to duplciate an expression with DupExp()... in that case we * want to dup the expression tree but use the same types. */ Type * DupType(SemGroup *sg, Type *stype) { Type *type = NULL; if (sg == NULL) return(stype); /* * XXX type may be resolved if it is part of a varargs dup */ #if 0 dassert_type(stype, (stype->ty_Flags & (TF_RESOLVED|TF_RESOLVING)) == 0); #endif switch(stype->ty_Op) { case TY_CLASS: /* * This only occurs because the resolver has resolved an * unresolved type on the original SemGroup. We duplicate * that on the new SemGroup. */ type = AllocClassType(&sg->sg_ClassList, stype->ty_ClassType.et_Super, stype->ty_ClassType.et_SemGroup, stype->ty_Visibility); break; case TY_IMPORT: case TY_DYNAMIC: type = stype; break; case TY_CPTRTO: type = TypeToCPtrType(DupType(sg, stype->ty_CPtrType.et_Type)); break; case TY_PTRTO: type = TypeToPtrType(DupType(sg, stype->ty_PtrType.et_Type)); break; case TY_REFTO: type = TypeToRefType(DupType(sg, stype->ty_RefType.et_Type)); break; case TY_ARYOF: type = TypeToAryType(DupType(sg, stype->ty_AryType.et_Type), SetDupExp(sg, stype->ty_AryType.et_ArySize), stype->ty_AryType.et_SemGroup); type->ty_AryType.et_Count = stype->ty_AryType.et_Count; break; case TY_VAR: type = TypeToVarType(DupType(sg, stype->ty_VarType.et_Type), DupSemGroup(sg, NULL, stype->ty_VarType.et_SemGroup, 1)); break; case TY_COMPOUND: type = AllocCompoundType( DupSemGroup(sg, NULL, stype->ty_CompType.et_SemGroup, 1)); break; case TY_ARGS: /* * At the moment we always formally duplicate the arguments * so we can modify them for methods below. */ type = AllocArgsType( DupSemGroup(sg, NULL, stype->ty_CompType.et_SemGroup, 1)); break; case TY_PROC: type = DupType(sg, stype->ty_ProcType.et_RetType); type = TypeToProcType(type, DupType(sg, stype->ty_ProcType.et_ArgsType), 1); /* * If this is a method procedure, we have to change the * first argument to point at our new subclass. It was * previously pointing at our superclass. XXX the * programmer can override the argument. If it isn't a * reference we have to assert. */ if (sg->sg_Stmt->st_Op != ST_Class) { /* * XXX probably an inlined procedure, the type is * already correct. Need an assertrion here. */ } else if (stype->ty_SQFlags & SF_METHOD) { SemGroup *asg = type->ty_ProcType.et_ArgsType->ty_ArgsType.et_SemGroup; Declaration *d = RUNE_FIRST(&asg->sg_DeclList); Type *thisType = d->d_StorDecl.ed_Type; dassert_decl(d, d->d_Id == String_This && d->d_Op == DOP_ARGS_STORAGE); dassert_decl(d, sg->sg_Stmt->st_Op == ST_Class); if (thisType->ty_Op == TY_CLASS) { /* XXX sg_ClassList? right sg? */ /* XXX correct visibility? */ if (d->d_Search == NULL) { d->d_Search = d->d_StorDecl.ed_Type-> ty_ClassType.et_SemGroup; } d->d_StorDecl.ed_Type = AllocClassType(&sg->sg_ClassList, sg->sg_Stmt->st_ClassStmt.es_Super, sg->sg_Stmt->st_MyGroup, SCOPE_ALL_VISIBLE); } else { dassert_decl(d, thisType->ty_Op == TY_REFTO); } } else if (stype->ty_SQFlags & SF_GMETHOD) { SemGroup *asg; Declaration *d; asg = type->ty_ProcType.et_ArgsType-> ty_ArgsType.et_SemGroup; d = RUNE_FIRST(&asg->sg_DeclList); dassert_decl(d, d->d_Id == String_This && d->d_Op == DOP_TYPEDEF); dassert_decl(d, sg->sg_Stmt->st_Op == ST_Class); dassert_decl(d, d->d_TypedefDecl.ed_Type->ty_Op == TY_CLASS); /* XXX sg_ClassList? right sg? */ /* XXX correct visibility? */ if (d->d_Search == NULL) { d->d_Search = d->d_TypedefDecl.ed_Type-> ty_ClassType.et_SemGroup; } d->d_TypedefDecl.ed_Type = AllocClassType(&sg->sg_ClassList, sg->sg_Stmt->st_ClassStmt.es_Super, sg->sg_Stmt->st_MyGroup, SCOPE_ALL_VISIBLE); } break; case TY_STORAGE: type = stype; break; case TY_UNRESOLVED: /* * e.g. so elements in a superclass will see refined elements * in the subclass. Note that the original import semgroup * is left intact so the semantic search mechanism uses it * when the base sg (typically a subclass) fails. */ type = AllocUnresolvedType( stype->ty_UnresType.et_ImportSemGroup, sg, stype->ty_UnresType.et_DottedId, 0); break; default: dassert_type(stype, 0); } if (type != stype) { type->ty_Flags = stype->ty_Flags & ~(TF_ISINTERNAL | TF_RESOLVING | TF_RESOLVED | TF_ALIGNRESOLVED | TF_TMPRESOLVED); type->ty_Bytes = stype->ty_Bytes; type->ty_AlignMask = stype->ty_AlignMask; type->ty_Visibility = stype->ty_Visibility; type->ty_DynamicVector = stype->ty_DynamicVector; } if (stype->ty_AssExp || stype->ty_SQFlags != type->ty_SQFlags) { type = TypeToQualType(type, NULL, stype->ty_SQFlags, SetDupExp(sg, stype->ty_AssExp)); } return(type); } typereglist_t TypeRegList = RUNE_HEAD_INITIALIZER(TypeRegList); void InternalRegisterType(const char *str, const char *linkname, Type *type) { static int Special = SPECIALF_REGISTERED|SPECIALF_INTERNAL|1; TypeRegNode *tr; dassert(Special & SPECIALF_MASK); tr = zalloc(sizeof(TypeRegNode)); tr->tr_Id = StrTableAlloc(str, strlen(str), Special++); tr->tr_Type = type; tr->tr_LinkName = linkname; RUNE_INSERT_TAIL(&TypeRegList, tr, tr_Node); } Type * InternalRegisteredTypeLookup(string_t id) { TypeRegNode *tr; RUNE_FOREACH(tr, &TypeRegList, tr_Node) { if (tr->tr_Id == id) return(tr->tr_Type); } return(NULL); }