Implement nominal class and interface types across declarations and calls
Build / AerScript (push) Successful in 37s

This commit is contained in:
2026-10-29 15:48:44 +01:00
parent 5f75319be9
commit 4f6dd45058
6 changed files with 534 additions and 193 deletions
+80 -3
View File
@@ -394,6 +394,40 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) {
}
return SXERR_NOMATCH;
}
/* Apply only to owned storage. Array copies are made before this walk, so a
* wider destination never weakens the source array's leaf contracts. */
PH7_PRIVATE void PH7_MemObjSetDeclaredType(ph7_value *pValue, sxu32 nType) {
ph7_hashmap_node *pNode;
ph7_hashmap *pMap;
if(nType & MEMOBJ_NAMED) {
PH7_VmTypeClass(pValue->pVm, nType, TRUE);
} else {
nType = 0;
}
pValue->nDeclaredType = nType;
if(nType) {
pValue->iFlags = MEMOBJ_VARIABLE;
}
if(nType && MemObjIsNullReference(pValue)) {
pValue->nType = nType & MEMOBJ_TYPEMASK;
pValue->x.pOther = 0;
if(nType & MEMOBJ_HASHMAP) {
pValue->x.pOther = PH7_NewHashmap(pValue->pVm, 0, 0);
if(pValue->x.pOther == 0) {
PH7_VmMemoryError(pValue->pVm);
}
}
}
if((pValue->nType & MEMOBJ_HASHMAP) == 0 || pValue->x.pOther == 0) {
return;
}
pMap = (ph7_hashmap *)pValue->x.pOther;
pMap->nDeclaredType = nType & ~MEMOBJ_HASHMAP;
for(pNode = pMap->pFirst; pNode; pNode = pNode->pPrev) {
ph7_value *pLeaf = (ph7_value *)SySetAt(&pValue->pVm->aMemObj, pNode->nValIdx);
PH7_MemObjSetDeclaredType(pLeaf, nType ? pMap->nDeclaredType | (pLeaf->nType & MEMOBJ_HASHMAP) : 0);
}
}
/*
* Duplicate safely the contents of a ph7_value if source and
* destination are of the compatible data types.
@@ -403,6 +437,38 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) {
ph7_vm *pVm = (pSrc->nType & MEMOBJ_HASHMAP) ? pDest->pVm : 0;
sxu32 nDest = pVm ? pDest->nIdx : SXU32_HIGH;
sxi32 bArena = pVm && SySetAt(&pVm->aMemObj, nDest) == pDest;
if(pDest->nDeclaredType & MEMOBJ_NAMED) {
sxu32 nDeclared = pDest->nDeclaredType;
sxi32 iFlags = pDest->iFlags;
ph7_value sValue, sPrevious;
sxi32 rc;
if(PH7_VmTypeCheck(pSrc, nDeclared) != SXRET_OK) {
return SXERR_NOMATCH;
}
/* Retain both payloads until storage has its contract again. Releasing
* the old object/map may invoke a destructor which writes through an
* alias of this binding. The source can also be the destination itself. */
PH7_MemObjInit(pDest->pVm, &sValue);
PH7_MemObjInit(pDest->pVm, &sPrevious);
PH7_MemObjLoad(pSrc, &sValue);
PH7_MemObjLoad(pDest, &sPrevious);
PH7_MemObjRelease(pDest);
pDest->x.pOther = 0;
if(MemObjIsNullReference(&sValue)) {
rc = SXRET_OK;
} else {
rc = PH7_MemObjStore(&sValue, pDest);
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
pDest->nType = nDeclared & MEMOBJ_TYPEMASK;
}
PH7_MemObjSetDeclaredType(pDest, nDeclared);
pDest->iFlags = iFlags;
PH7_MemObjRelease(&sValue);
PH7_MemObjRelease(&sPrevious);
return rc;
}
if(pDest->nType == 0 || pDest->nType == MEMOBJ_NULL || pDest->nType == pSrc->nType) {
sxu32 nType = pSrc->nType;
PH7_MemObjStore(pSrc, pDest);
@@ -465,6 +531,10 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) {
} else {
return SXERR_NOMATCH;
}
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
PH7_MemObjSetDeclaredType(pDest, 0);
return SXRET_OK;
}
/*
@@ -957,7 +1027,10 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
if((pDest->nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP)) == MEMOBJ_OBJ) {
pObj = (ph7_class_instance *)pDest->x.pOther;
}
SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
pDest->x = pSrc->x;
pDest->iFlags = pSrc->iFlags;
pDest->nType = pSrc->nType;
pDest->nDeclaredType = pSrc->nDeclaredType;
rc = SXRET_OK;
if(SyBlobLength(&pSrc->sBlob) > 0) {
SyBlobReset(&pDest->sBlob);
@@ -976,6 +1049,7 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
* Stack destinations have no arena slot and must not be rebound. */
pMap = PH7_NewHashmap(pVm, 0, 0);
PH7_HashmapDup(pSrcMap, pMap);
pMap->nDeclaredType = pSrcMap->nDeclaredType;
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
@@ -991,8 +1065,10 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
* buffer contents,simply point to it.
*/
PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) {
SyMemcpy((const void *) & (*pSrc), &(*pDest),
sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
pDest->x = pSrc->x;
pDest->iFlags = pSrc->iFlags;
pDest->nType = pSrc->nType;
pDest->nDeclaredType = pSrc->nDeclaredType;
if(pSrc->x.pOther) {
if(pSrc->nType & MEMOBJ_HASHMAP) {
/* Increment reference count */
@@ -1014,6 +1090,7 @@ PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) {
* Invalidate any prior representation of a given ph7_value.
*/
PH7_PRIVATE sxi32 PH7_MemObjRelease(ph7_value *pObj) {
pObj->nDeclaredType = 0;
if((pObj->nType & MEMOBJ_NULL) == 0) {
if(pObj->x.pOther) {
if(pObj->nType & MEMOBJ_HASHMAP) {