mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
Adding Obsolete/Error/Warn attributes, devirt fixes for struct ptr
This commit is contained in:
parent
1aded38e36
commit
ad2542eba6
4 changed files with 261 additions and 22 deletions
|
@ -319,7 +319,6 @@ namespace System
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
/// Generally used as a per-method optimization, [DisableObjectAccessChecks] will avoid the runtime per-object-access
|
||||
/// checks which by default are only applied in debug builds anyway.
|
||||
[AttributeUsage(AttributeTargets.Method/*, AlwaysIncludeTarget=true*/)]
|
||||
|
@ -327,6 +326,38 @@ namespace System
|
|||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct ObsoleteAttribute : Attribute
|
||||
{
|
||||
public this(bool isError)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public this(String error, bool isError)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct ErrorAttribute : Attribute
|
||||
{
|
||||
public this(String error)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct WarnAttribute : Attribute
|
||||
{
|
||||
public this(String error)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// If [NoDiscard] is used on a method, the the compiler will show a warning if the result is discarded.
|
||||
/// If used on a type, the compiler will show an warning if any method returns that type and the caller discards the result.
|
||||
[AttributeUsage(.Method | .Class | .Struct)]
|
||||
|
|
|
@ -332,6 +332,38 @@ namespace System
|
|||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct ObsoleteAttribute : Attribute
|
||||
{
|
||||
public this(bool isError)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public this(String error, bool isError)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct ErrorAttribute : Attribute
|
||||
{
|
||||
public this(String error)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Constructor)]
|
||||
public struct WarnAttribute : Attribute
|
||||
{
|
||||
public this(String error)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Method | .Class | .Struct)]
|
||||
public struct NoDiscardAttribute : Attribute
|
||||
{
|
||||
|
|
|
@ -1660,7 +1660,7 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
|||
return mBestMethodDef != NULL;
|
||||
}
|
||||
|
||||
void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target)
|
||||
void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* origTarget, BfTypedValue* staticResult)
|
||||
{
|
||||
if ((mBestMethodDef == NULL) || (target.mType == NULL))
|
||||
return;
|
||||
|
@ -1687,6 +1687,17 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target)
|
|||
{
|
||||
BfTypeInterfaceEntry* bestIFaceEntry = NULL;
|
||||
auto checkTypeInst = checkType->ToTypeInstance();
|
||||
|
||||
if (mBestMethodTypeInstance->mTypeDef == mModule->mCompiler->mIHashableTypeDef)
|
||||
{
|
||||
if ((origTarget != NULL) && (origTarget->mType->IsPointer()) && (staticResult != NULL))
|
||||
{
|
||||
BfTypedValue ptrVal = mModule->LoadValue(*origTarget);
|
||||
*staticResult = BfTypedValue(mModule->mBfIRBuilder->CreatePtrToInt(ptrVal.mValue, BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (checkTypeInst != NULL)
|
||||
{
|
||||
mModule->PopulateType(checkTypeInst, BfPopulateType_DataAndMethods);
|
||||
|
@ -1723,6 +1734,13 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target)
|
|||
if (bestIFaceEntry != NULL)
|
||||
break;
|
||||
checkTypeInst = checkTypeInst->mBaseType;
|
||||
|
||||
if ((checkTypeInst == NULL) && (checkType->HasWrappedRepresentation()))
|
||||
{
|
||||
auto underlyingType = checkType->GetUnderlyingType();
|
||||
if ((underlyingType != NULL) && (underlyingType->IsWrappableType()))
|
||||
checkTypeInst = mModule->GetWrappedStructType(underlyingType);
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIFaceEntry != NULL)
|
||||
|
@ -3689,6 +3707,82 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
|||
autoComplete->mIgnoreFixits = hadIgnoredFixits;
|
||||
}
|
||||
|
||||
void BfExprEvaluator::PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc)
|
||||
{
|
||||
BfCustomAttributes* customAttributes = methodInstance->GetCustomAttributes();
|
||||
if (customAttributes != NULL)
|
||||
{
|
||||
auto _AddMethodDeclarationMoreInfo = [&]()
|
||||
{
|
||||
if (methodInstance->mMethodDef->mMethodDeclaration != NULL)
|
||||
mModule->mCompiler->mPassInstance->MoreInfo(
|
||||
StrFormat("See method declaration '%s'", mModule->MethodToString(methodInstance).c_str()),
|
||||
methodInstance->mMethodDef->GetRefNode());
|
||||
};
|
||||
|
||||
BfIRConstHolder* constHolder = methodInstance->GetOwner()->mConstHolder;
|
||||
auto customAttribute = customAttributes->Get(mModule->mCompiler->mObsoleteAttributeTypeDef);
|
||||
if ((customAttribute != NULL) && (!customAttribute->mCtorArgs.IsEmpty()))
|
||||
{
|
||||
String err;
|
||||
err = StrFormat("'%s' is obsolete", mModule->MethodToString(methodInstance).c_str());
|
||||
|
||||
bool isError = false;
|
||||
|
||||
auto constant = constHolder->GetConstant(customAttribute->mCtorArgs[0]);
|
||||
if (constant->mTypeCode == BfTypeCode_Boolean)
|
||||
{
|
||||
isError = constant->mBool;
|
||||
}
|
||||
else if (customAttribute->mCtorArgs.size() >= 2)
|
||||
{
|
||||
String* str = mModule->GetStringPoolString(customAttribute->mCtorArgs[0], constHolder);
|
||||
if (str != NULL)
|
||||
{
|
||||
err += ":\n '";
|
||||
err += *str;
|
||||
err += "'";
|
||||
}
|
||||
|
||||
constant = constHolder->GetConstant(customAttribute->mCtorArgs[1]);
|
||||
isError = constant->mBool;
|
||||
}
|
||||
|
||||
BfError* error = NULL;
|
||||
if (isError)
|
||||
error = mModule->Fail(err, targetSrc);
|
||||
else
|
||||
error = mModule->Warn(0, err, targetSrc);
|
||||
if (error != NULL)
|
||||
_AddMethodDeclarationMoreInfo();
|
||||
}
|
||||
|
||||
customAttribute = customAttributes->Get(mModule->mCompiler->mErrorAttributeTypeDef);
|
||||
if ((customAttribute != NULL) && (!customAttribute->mCtorArgs.IsEmpty()))
|
||||
{
|
||||
String err = StrFormat("Method error: '", mModule->MethodToString(methodInstance).c_str());
|
||||
String* str = mModule->GetStringPoolString(customAttribute->mCtorArgs[0], constHolder);
|
||||
if (str != NULL)
|
||||
err += *str;
|
||||
err += "'";
|
||||
if (mModule->Fail(err, targetSrc) != NULL)
|
||||
_AddMethodDeclarationMoreInfo();
|
||||
}
|
||||
|
||||
customAttribute = customAttributes->Get(mModule->mCompiler->mWarnAttributeTypeDef);
|
||||
if ((customAttribute != NULL) && (!customAttribute->mCtorArgs.IsEmpty()))
|
||||
{
|
||||
String err = StrFormat("Method warning: '", mModule->MethodToString(methodInstance).c_str());
|
||||
String* str = mModule->GetStringPoolString(customAttribute->mCtorArgs[0], constHolder);
|
||||
if (str != NULL)
|
||||
err += *str;
|
||||
err += "'";
|
||||
if (mModule->Warn(0, err, targetSrc) != NULL)
|
||||
_AddMethodDeclarationMoreInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret, bool isTailCall)
|
||||
{
|
||||
// static int sCallIdx = 0;
|
||||
|
@ -5926,7 +6020,10 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
methodMatcher.CheckType(lookupTypeInst, target, true);
|
||||
}
|
||||
|
||||
methodMatcher.TryDevirtualizeCall(target);
|
||||
BfTypedValue staticResult;
|
||||
methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult);
|
||||
if (staticResult)
|
||||
return staticResult;
|
||||
bypassVirtual |= methodMatcher.mBypassVirtual;
|
||||
|
||||
if (methodMatcher.mBestMethodDef != NULL)
|
||||
|
@ -6660,6 +6757,8 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
}
|
||||
}
|
||||
|
||||
PerformCallChecks(moduleMethodInstance.mMethodInstance, targetSrc);
|
||||
|
||||
if (result)
|
||||
{
|
||||
bool discardedReturnValue = mUsedAsStatement;
|
||||
|
@ -6672,15 +6771,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
auto customAttribute = customAttributes->Get(mModule->mCompiler->mNoDiscardAttributeTypeDef);
|
||||
if (!customAttribute->mCtorArgs.IsEmpty())
|
||||
{
|
||||
int strId = mModule->GetStringPoolIdx(customAttribute->mCtorArgs[0], constHolder);
|
||||
if (strId != -1)
|
||||
String* str = mModule->GetStringPoolString(customAttribute->mCtorArgs[0], constHolder);
|
||||
if ((str != NULL) && (!str->IsEmpty()))
|
||||
{
|
||||
auto& entry = mModule->mContext->mStringObjectIdMap[strId];
|
||||
if (!entry.mString.IsEmpty())
|
||||
{
|
||||
mModule->Warn(0, text + ": " + entry.mString, targetSrc);
|
||||
return;
|
||||
}
|
||||
mModule->Warn(0, text + ": " + *str, targetSrc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7562,6 +7657,70 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
|
|||
_Int32Result((typeInstance != NULL) ? typeInstance->mInstAlign : type->mSize);
|
||||
else if (memberName == "InstanceStride")
|
||||
_Int32Result((typeInstance != NULL) ? typeInstance->GetInstStride() : type->GetStride());
|
||||
else if ((memberName == "MinValue") || (memberName == "MaxValue"))
|
||||
{
|
||||
bool isMin = memberName == "MinValue";
|
||||
|
||||
BfType* checkType = typeInstance;
|
||||
if (checkType->IsTypedPrimitive())
|
||||
checkType = checkType->GetUnderlyingType();
|
||||
|
||||
if (checkType->IsPrimitiveType())
|
||||
{
|
||||
auto primType = (BfPrimitiveType*)checkType;
|
||||
|
||||
if (typeInstance->IsEnum())
|
||||
{
|
||||
if (typeInstance->mTypeInfoEx != NULL)
|
||||
{
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? (uint64)typeInstance->mTypeInfoEx->mMinValue : (uint64)typeInstance->mTypeInfoEx->mMaxValue), typeInstance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (primType->mTypeDef->mTypeCode)
|
||||
{
|
||||
case BfTypeCode_Int8:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? -0x80 : 0x7F), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_Int16:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? -0x8000 : 0x7FFF), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_Int32:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? (uint64)-0x80000000LL : 0x7FFFFFFF), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_Int64:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? (uint64)-0x8000000000000000LL : (uint64)0x7FFFFFFFFFFFFFFFLL), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_UInt8:
|
||||
case BfTypeCode_Char8:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? 0 : 0xFF), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_UInt16:
|
||||
case BfTypeCode_Char16:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? 0 : 0xFFFF), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_UInt32:
|
||||
case BfTypeCode_Char32:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? 0 : (uint64)0xFFFFFFFFLL), typeInstance);
|
||||
return true;
|
||||
case BfTypeCode_UInt64:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? 0 : (uint64)0xFFFFFFFFFFFFFFFFLL), typeInstance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeInstance->IsEnum())
|
||||
{
|
||||
mModule->Fail("'MinValue' cannot be used on enums with payloads", propName);
|
||||
}
|
||||
else
|
||||
{
|
||||
mModule->Fail(StrFormat("'%s' cannot be used on type '%s'", memberName.c_str(), mModule->TypeToString(typeInstance).c_str()), propName);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@ -11290,7 +11449,21 @@ BfTypedValue BfExprEvaluator::MakeCallableTarget(BfAstNode* targetSrc, BfTypedVa
|
|||
{
|
||||
auto primStructType = mModule->GetWrappedStructType(target.mType);
|
||||
if (primStructType != NULL)
|
||||
{
|
||||
mModule->PopulateType(primStructType);
|
||||
target.mType = primStructType;
|
||||
if ((primStructType->IsSplattable()) && (!primStructType->IsTypedPrimitive()))
|
||||
{
|
||||
if (target.IsAddr())
|
||||
{
|
||||
auto ptrType = mModule->CreatePointerType(primStructType);
|
||||
target = BfTypedValue(mModule->mBfIRBuilder->CreateBitCast(target.mValue, mModule->mBfIRBuilder->MapType(ptrType)), primStructType, true);
|
||||
}
|
||||
else
|
||||
target.mKind = BfTypedValueKind_SplatHead;
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -12981,7 +13154,7 @@ void BfExprEvaluator::Visit(BfInvocationExpression* invocationExpr)
|
|||
checkTarget = indexerExpr->mTarget;
|
||||
|
||||
if (indexerExpr->mCommas.size() != 0)
|
||||
mModule->Fail("Only one value expected. Consider adding an allocation specifier such as 'new' if construction of a dynamic multidimentional was intended.", indexerExpr->mCommas[0]);
|
||||
mModule->Fail("Only one value expected. Consider adding an allocation specifier such as 'new' if construction of a dynamic multidimensional was intended.", indexerExpr->mCommas[0]);
|
||||
|
||||
int arrSize = 0;
|
||||
|
||||
|
@ -13161,10 +13334,11 @@ BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* m
|
|||
if (!checkedUnderlying)
|
||||
{
|
||||
checkedUnderlying = true;
|
||||
if (checkType->IsTypedPrimitive())
|
||||
if (checkType->HasWrappedRepresentation())
|
||||
{
|
||||
auto underlyingType = checkType->GetUnderlyingType();
|
||||
checkTypeInst = mModule->GetWrappedStructType(underlyingType);
|
||||
if (underlyingType != NULL)
|
||||
checkTypeInst = mModule->GetWrappedStructType(underlyingType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13257,6 +13431,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
|
|||
mModule->UpdateExprSrcPos(mPropSrc);
|
||||
|
||||
CheckPropFail(matchedMethod, methodInstance.mMethodInstance);
|
||||
PerformCallChecks(methodInstance.mMethodInstance, mPropSrc);
|
||||
|
||||
if (methodInstance.mMethodInstance->IsSkipCall())
|
||||
{
|
||||
|
|
|
@ -167,7 +167,7 @@ public:
|
|||
void CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass);
|
||||
bool WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInstance* startTypeInstance, BfTypeInstance* checkTypeInstance, BfMethodDef* methodDef);
|
||||
bool CheckMethod(BfTypeInstance* typeInstance, BfMethodDef* checkMethod, bool isFailurePass);
|
||||
void TryDevirtualizeCall(BfTypedValue target);
|
||||
void TryDevirtualizeCall(BfTypedValue target, BfTypedValue* origTarget = NULL, BfTypedValue* staticResult = NULL);
|
||||
};
|
||||
|
||||
|
||||
|
@ -345,6 +345,7 @@ public:
|
|||
BfTypedValue LookupIdentifier(BfAstNode* identifierNode, const StringImpl& findName, bool ignoreInitialError = false, bool* hadError = NULL);
|
||||
BfTypedValue LookupIdentifier(BfIdentifierNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL);
|
||||
void AddCallDependencies(BfMethodInstance* methodInstance);
|
||||
void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc);
|
||||
BfTypedValue CreateCall(BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret = NULL, bool isTailCall = false);
|
||||
BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, bool bypassVirtual, SizedArrayImpl<BfResolvedArg>& argValues, bool skipThis = false);
|
||||
BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue