Turn Map/Array assignments into Copy

Better error checking for struct assignment

Lock assignments behind version, don't break or "fix" existing code using older ZScript versions
This commit is contained in:
Ricardo Luís Vaz Silva 2023-03-05 12:20:35 -03:00 committed by Christoph Oelckers
parent a13b19815c
commit b9104e8aa9

View file

@ -2454,7 +2454,17 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
SAFE_RESOLVE(Right, ctx);
}
}
else if (Base->ValueType == Right->ValueType)
else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
{
// allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers.
// For all other types this is not needed. Structs are not assignable and classes can only exist as references.
Right->RequestAddress(ctx, nullptr);
Right->ValueType = Base->ValueType;
}
else if ( Base->ValueType == Right->ValueType
|| (Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
|| (Right->ValueType->isRealPointer() && Right->ValueType->toPointer()->PointedType == Base->ValueType)
)
{
if (Base->ValueType->isArray())
{
@ -2462,28 +2472,97 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
delete this;
return nullptr;
}
else if (Base->IsDynamicArray())
else if(!Base->IsVector() && !Base->IsQuaternion())
{
ScriptPosition.Message(MSG_ERROR, "Cannot assign dynamic arrays, use Copy() or Move() function instead");
delete this;
return nullptr;
}
if (!Base->IsVector() && !Base->IsQuaternion() && Base->ValueType->isStruct())
{
ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet");
delete this;
return nullptr;
PType * btype = Base->ValueType;
if(btype->isRealPointer())
{
PType * p = static_cast<PPointer *>(btype)->PointedType;
if( p->isDynArray() || p->isMap()
|| (p->isStruct() && !static_cast<PStruct*>(p)->isNative)
)
{ //un-pointer dynarrays, maps and non-native structs for assignment checking
btype = p;
}
}
if (btype->isDynArray())
{
if(ctx.Version >= MakeVersion(4, 11, 0))
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
}
else
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{
ScriptPosition.Message(MSG_WARNING, "Dynamic Array assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead\n"
TEXTCOLOR_RED "!! Assigning an out array pointer to another out array pointer does not alter either of the underlying arrays' values below ZScript version 4.11 !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Dynamic Array assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead");
delete this;
return nullptr;
}
}
}
else if (btype->isMap())
{
if(ctx.Version >= MakeVersion(4, 11, 0))
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
}
else
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{ // don't break existing code, but warn that it's a no-op
ScriptPosition.Message(MSG_WARNING, "Map assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead\n"
TEXTCOLOR_RED "!! Assigning an out map pointer to another out map pointer does not alter either of the underlying maps' values below ZScript version 4.11 !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Map assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead");
delete this;
return nullptr;
}
}
}
else if (btype->isMapIterator())
{
ScriptPosition.Message(MSG_ERROR, "Cannot assign map iterators");
delete this;
return nullptr;
}
else if (btype->isStruct())
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{ // don't break existing code, but warn that it's a no-op
ScriptPosition.Message(MSG_WARNING, "Struct assignment not implemented yet\n"
TEXTCOLOR_RED "!! Assigning an out struct pointer to another out struct pointer does not alter either of the underlying structs' values !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet");
delete this;
return nullptr;
}
}
}
// Both types are the same so this is ok.
}
else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
{
// allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers.
// For all other types this is not needed. Structs are not assignable and classes can only exist as references.
bool writable;
Right->RequestAddress(ctx, &writable);
Right->ValueType = Base->ValueType;
}
else
{
// pass it to FxTypeCast for complete handling.