1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00

Comptime can now run on unspecialized code

This commit is contained in:
Brian Fiete 2022-01-16 07:59:51 -05:00
parent a4a5d99fd0
commit 4e18517c03
13 changed files with 289 additions and 155 deletions

View file

@ -381,7 +381,15 @@ namespace System
{
get
{
return (mTypeFlags & (TypeFlags.SpecializedGeneric | TypeFlags.UnspecializedGeneric)) != 0;
return (mTypeFlags & (.SpecializedGeneric | .UnspecializedGeneric)) != 0;
}
}
public bool IsGenericParam
{
get
{
return (mTypeFlags & .GenericParam) != 0;
}
}
@ -641,6 +649,8 @@ namespace System
}
}
enum TypeCode : uint8
{
None,
@ -1298,6 +1308,7 @@ namespace System.Reflection
Delegate = 0x20000,
Function = 0x40000,
HasDestructor = 0x80000,
GenericParam = 0x100000,
}
public enum FieldFlags : uint16

View file

@ -1094,13 +1094,25 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
if (typeInst->mTypeDef->mEmitParent != NULL)
{
auto emitTypeDef = typeInst->mTypeDef;
auto emitTypeDef = typeInst->mTypeDef;
typeInst->mTypeDef = emitTypeDef->mEmitParent;
BfLogSysM("Type %p queueing delete of typeDef %p, resetting typeDef to %p\n", typeInst, emitTypeDef, typeInst->mTypeDef);
emitTypeDef->mDefState = BfTypeDef::DefState_Deleted;
AutoCrit autoCrit(mSystem->mDataLock);
BF_ASSERT(!mSystem->mTypeDefDeleteQueue.Contains(emitTypeDef));
mSystem->mTypeDefDeleteQueue.push_back(emitTypeDef);
if (emitTypeDef->mDefState != BfTypeDef::DefState_Deleted)
{
emitTypeDef->mDefState = BfTypeDef::DefState_Deleted;
AutoCrit autoCrit(mSystem->mDataLock);
BF_ASSERT(!mSystem->mTypeDefDeleteQueue.Contains(emitTypeDef));
mSystem->mTypeDefDeleteQueue.push_back(emitTypeDef);
for (auto& dep : typeInst->mDependencyMap)
{
if (auto typeInst = dep.mKey->ToTypeInstance())
{
if (typeInst->mTypeDef == emitTypeDef)
RebuildType(typeInst);
}
}
}
}
//typeInst->mTypeDef->ClearEmitted();

View file

@ -2664,7 +2664,7 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* ori
if ((mModule->mCompiler->IsAutocomplete()) || (mModule->mContext->mResolvingVarField))
return;
if ((mModule->mBfIRBuilder->mIgnoreWrites) && (!mBestMethodDef->mIsConcrete))
if ((mModule->mBfIRBuilder->mIgnoreWrites) && (!mBestMethodDef->mIsConcrete) && (!mBestMethodTypeInstance->IsInterface()))
return;
if (mBestMethodTypeInstance->IsInterface())
@ -3443,7 +3443,7 @@ void BfExprEvaluator::Visit(BfCaseExpression* caseExpr)
}
if ((caseValAddr) && (caseValAddr.mType->IsVar()))
if ((caseValAddr) && (IsVar(caseValAddr.mType)))
{
auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(caseExpr->mCaseExpression);
if (invocationExpr != NULL)
@ -3519,6 +3519,18 @@ static bool IsCharType(BfTypeCode typeCode)
}
}
bool BfExprEvaluator::IsVar(BfType* type)
{
if (type->IsVar())
return true;
if ((type->IsGenericParam()) && (!mModule->mBfIRBuilder->mIgnoreWrites))
{
BF_ASSERT(mModule->mIsComptimeModule);
return true;
}
return false;
}
void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant)
{
switch (variant.mTypeCode)
@ -4298,7 +4310,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
}
}
if ((target.mType != NULL) && (target.mType->IsVar()))
if ((target.mType != NULL) && (IsVar(target.mType)))
return BfTypedValue(mModule->GetDefaultValue(target.mType), target.mType, true);
BfTypeInstance* startCheckType = mModule->mCurTypeInstance;
@ -4496,7 +4508,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
mResultFieldInstance = fieldInstance;
// Are we accessing a 'var' field that has not yet been resolved?
if (fieldInstance->mResolvedType->IsVar())
if (IsVar(fieldInstance->mResolvedType))
{
// This can happen if we have one var field referencing another var field
fieldInstance->mResolvedType = mModule->ResolveVarFieldType(curCheckType, fieldInstance, field);
@ -5779,7 +5791,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
{
// We're attempting to directly invoke a non-virtual interface method, this will happen during the unspecialized pass
// OR if we had an error and didn't find an implementing member in the actual target
if (!mModule->mCurMethodInstance->mIsUnspecialized)
if ((!mModule->mCurMethodInstance->mIsUnspecialized) && (!mModule->mCurTypeInstance->IsInterface()))
mModule->AssertErrorState();
if (returnType->IsInterface())
@ -5814,7 +5826,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
return BfTypedValue();
}
if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized))
if (((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized)) && (mModule->mBfIRBuilder->mIgnoreWrites))
{
// Don't actually do the call - our target may be a generic param
return _GetDefaultReturnValue();
@ -6248,7 +6260,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl<BfIRValue>& ir
{
MakeBaseConcrete(argVal);
if (argVal.mType->IsVar())
if (IsVar(argVal.mType))
{
argVal = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType);
}
@ -6774,9 +6786,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
}
wantType = methodInstance->GetParamType(paramIdx);
if (wantType->IsSelf())
wantType = methodInstance->GetOwner();
if (wantType->IsVar())
if (!mModule->mCurTypeInstance->IsInterface())
{
// Resolve `Self` types
if (wantType->IsUnspecializedTypeVariation())
wantType = mModule->ResolveGenericType(wantType, NULL, NULL);
}
if (IsVar(wantType))
{
// Case happens when we can't find the argument type
failed = true;
@ -8109,7 +8126,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
}
}
if ((!target.mType->IsGenericParam()) && (!target.IsSplat()) && (!target.mType->IsVar()))
if ((!target.mType->IsGenericParam()) && (!target.IsSplat()) && (!IsVar(target.mType)))
target = MakeCallableTarget(targetSrc, target);
}
@ -8181,7 +8198,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
}
}
}
else if (target.mType->IsVar())
else if (IsVar(target.mType))
isUnboundCall = true;
}
@ -8238,12 +8255,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
bool wantsExtensionCheck = target;
auto targetType = target.mType;
BfTypeDef* curTypeDef = NULL;
BfType* selfType = NULL;
BfTypeInstance* targetTypeInst = NULL;
bool checkNonStatic = true;
if (target)
{
if (targetType->IsVar())
if (IsVar(targetType))
return mModule->GetDefaultTypedValue(targetType);
targetTypeInst = targetType->ToTypeInstance();
if (targetTypeInst != NULL)
@ -8312,6 +8330,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
curTypeDef = targetTypeInst->mTypeDef;
checkNonStatic = true;
target = mModule->GetThis();
selfType = mModule->mCurTypeInstance;
//target.mType = targetTypeInst;
}
else
@ -8529,7 +8548,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
}
BfTypedValue staticResult;
methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult);
//
{
auto devirtTarget = target;
if ((devirtTarget.mType == NULL) && (selfType != NULL))
devirtTarget.mType = selfType;
methodMatcher.TryDevirtualizeCall(devirtTarget, &origTarget, &staticResult);
}
if (staticResult)
return staticResult;
bypassVirtual |= methodMatcher.mBypassVirtual;
@ -8873,7 +8898,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
}
return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArguments, checkedKind);
}
if (fieldVal.mType->IsVar())
if (IsVar(fieldVal.mType))
{
FinishDeferredEvals(argValues);
return BfTypedValue(mModule->GetDefaultValue(fieldVal.mType), fieldVal.mType);
@ -9456,17 +9481,27 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
if (result)
{
if (result.mType->IsSelf())
if ((result.mType->IsUnspecializedTypeVariation()) && (moduleMethodInstance.mMethodInstance->GetOwner()->IsInterface()))
{
BfType* selfType = NULL;
if (methodMatcher.mSelfType != NULL)
{
BF_ASSERT(mModule->IsInGeneric());
result = mModule->GetDefaultTypedValue(methodMatcher.mSelfType);
selfType = methodMatcher.mSelfType;
}
else
else
{
// Will be an error
result = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance);
selfType = methodMatcher.mBestMethodTypeInstance;
}
if ((selfType != NULL) && (!selfType->IsInterface()))
{
SetAndRestoreValue<BfTypeInstance*> prevCurTypeInst(mModule->mCurTypeInstance, selfType->ToTypeInstance());
auto resolvedType = mModule->ResolveGenericType(result.mType, NULL, NULL);
if ((resolvedType != NULL) && (resolvedType != result.mType))
result = mModule->GetDefaultTypedValue(resolvedType);
}
}
}
@ -9537,7 +9572,7 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
auto origResult = mResult;
auto lookupType = BindGenericType(nameNode, mResult.mType);
if (mResult.mType->IsVar())
if (IsVar(mResult.mType))
{
mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true);
return;
@ -9696,9 +9731,10 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
mResult.mType = mResult.mType->GetUnderlyingType();
auto origResult = mResult;
if (mResult.mType->IsVar())
if (IsVar(mResult.mType))
{
mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true);
auto varType = mModule->GetPrimitiveType(BfTypeCode_Var);
mResult = BfTypedValue(mModule->GetDefaultValue(varType), varType, true);
return;
}
@ -10404,7 +10440,7 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr)
return;
}
if (type->IsGenericParam())
if ((type->IsGenericParam()) && (!mModule->mIsComptimeModule))
{
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(typeType)), typeType);
}
@ -10493,6 +10529,8 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
_BoolResult(type->IsNullable());
else if (memberName == "IsGenericType")
_BoolResult(type->IsGenericTypeInstance());
else if (memberName == "IsGenericParam")
_BoolResult(type->IsGenericParam());
else if (memberName == "IsArray")
_BoolResult(type->IsArray());
else if (memberName == "IsSizedArray")
@ -10658,7 +10696,7 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
else
return false;
if (type->IsGenericParam())
if ((type->IsGenericParam()) && (!mModule->mIsComptimeModule))
{
if (mResult.mType != NULL)
mResult = mModule->GetDefaultTypedValue(mResult.mType, false, Beefy::BfDefaultValueKind_Undef);
@ -11817,7 +11855,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
if (bindResult.mMethodInstance == NULL)
{
if ((mResult) && (mResult.mType->IsVar()))
if ((mResult) && (IsVar(mResult.mType)))
return;
mResult = BfTypedValue();
return;
@ -13563,7 +13601,7 @@ void BfExprEvaluator::Visit(BfLambdaBindExpression* lambdaBindExpr)
if (capturedValue)
{
if (!capturedTypedVal.mType->IsVar())
if (!IsVar(capturedTypedVal.mType))
{
auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mResult.mValue, 0, fieldInstance->mDataIdx);
mModule->mBfIRBuilder->CreateStore(capturedValue, fieldPtr);
@ -13942,7 +13980,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
}
resolvedTypeRef = unresolvedTypeRef;
if ((resolvedTypeRef != NULL) && (resolvedTypeRef->IsVar()))
if ((resolvedTypeRef != NULL) && (IsVar(resolvedTypeRef)))
resolvedTypeRef = unresolvedTypeRef;
}
@ -14300,7 +14338,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
BfInitContext initContext(mModule, resultType, dimensions, dimLengthVals, arraySize, writeIdx);
if (resultType->IsVar())
if (IsVar(resultType))
{
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
mResult = BfTypedValue(BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), mModule->GetPrimitiveType(BfTypeCode_Var)));
@ -14613,7 +14651,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
appendAllocAlign = BF_MAX(appendAllocAlign, allocAlign);
BfIRValue allocValue;
if (resolvedTypeRef->IsVar())
if (IsVar(resolvedTypeRef))
{
mResult = mModule->GetDefaultTypedValue(resultType);
return;
@ -14958,7 +14996,7 @@ BfTypedValue BfExprEvaluator::MakeCallableTarget(BfAstNode* targetSrc, BfTypedVa
target = mModule->MakeAddressable(target);
}
if (target.mType->IsVar())
if (IsVar(target.mType))
{
target.mType = mModule->mContext->mBfObjectType;
return target;

View file

@ -402,6 +402,7 @@ public:
BfExprEvaluator(BfModule* module);
~BfExprEvaluator();
bool IsVar(BfType* type);
void GetLiteral(BfAstNode* refNode, const BfVariant& variant);
void FinishExpressionResult();
virtual bool CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode);

View file

@ -2898,6 +2898,9 @@ bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool
else
methodInstance->mHasFailed = true;
if (!methodInstance->mHasStartedDeclaration)
StartMethodDeclaration(methodInstance, NULL);
bool isSpecializedMethod = ((methodInstance != NULL) && (!methodInstance->mIsUnspecialized) && (methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mMethodGenericArguments.size() != 0));
if (isSpecializedMethod)
{
@ -5393,6 +5396,9 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
typeDataSource = ResolveTypeDef(mCompiler->mReflectConstExprType)->ToTypeInstance();
else
typeDataSource = mContext->mBfTypeType;
if (type->IsGenericParam())
typeFlags |= BfTypeFlags_GenericParam;
if ((!mTypeDataRefs.ContainsKey(typeDataSource)) && (typeDataSource != type))
{
@ -11396,10 +11402,12 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
customAttributes->mAttributes.push_back(customAttribute);
continue;
}
SetAndRestoreValue<BfTypeInstance*> prevCurTypeInst(mContext->mUnreifiedModule->mCurTypeInstance, mCurTypeInstance);
SetAndRestoreValue<BfMethodInstance*> prevCurMethodInst(mContext->mUnreifiedModule->mCurMethodInstance, mCurMethodInstance);
if (mContext->mCurTypeState != NULL)
{
SetAndRestoreValue<BfTypeReference*> prevTypeRef(mContext->mCurTypeState->mCurAttributeTypeRef, attributesDirective->mAttributeTypeRef);
SetAndRestoreValue<BfTypeReference*> prevTypeRef(mContext->mCurTypeState->mCurAttributeTypeRef, attributesDirective->mAttributeTypeRef);
mContext->mUnreifiedModule->ResolveTypeResult(attributesDirective->mAttributeTypeRef, attrType, BfPopulateType_BaseType, (BfResolveTypeRefFlags)0);
}
else
@ -13820,11 +13828,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
{
methodInstance->mMangleWithIdx = true;
}
BfModule* declareModule = GetOrCreateMethodModule(methodInstance);
if ((doingRedeclare) && (methodInstance->mDeclModule != mContext->mUnreifiedModule))
declareModule = methodInstance->mDeclModule;
BF_ASSERT(typeInst == methodInstance->GetOwner());
auto methodDeclaration = methodDef->GetMethodDeclaration();
@ -13882,6 +13886,15 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
addToWorkList = false;
}
BfModule* declareModule;
//
{
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, methodInstance);
declareModule = GetOrCreateMethodModule(methodInstance);
}
if ((doingRedeclare) && (methodInstance->mDeclModule != mContext->mUnreifiedModule))
declareModule = methodInstance->mDeclModule;
BF_ASSERT(declareModule != NULL);
methodInstance->mDeclModule = declareModule;
@ -18685,7 +18698,7 @@ void BfModule::EmitGCFindTLSMembers()
CallChainedMethods(mCurMethodInstance, false);
}
void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, bool forceIRWrites)
{
BP_ZONE_F("BfModule::ProcessMethod %s", BP_DYN_STR(methodInstance->mMethodDef->mName.c_str()));
@ -18714,7 +18727,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
}
}
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || methodInstance->mIsUnspecialized);
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, (mWantsIRIgnoreWrites || methodInstance->mIsUnspecialized) && (!forceIRWrites));
if ((HasCompiledOutput()) && (!mBfIRBuilder->mIgnoreWrites))
{
@ -20680,7 +20693,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
mBfIRBuilder->MergeBlockDown(mCurMethodState->mIRInitBlock, mCurMethodState->mIREntryBlock);
mBfIRBuilder->MergeBlockDown(mCurMethodState->mIRHeadBlock, mCurMethodState->mIREntryBlock);
if ((mCurMethodInstance->mIsUnspecialized) /*|| (typeDef->mIsFunction)*/ || (mCurTypeInstance->IsUnspecializedType()))
if (((mCurMethodInstance->mIsUnspecialized) /*|| (typeDef->mIsFunction)*/ || (mCurTypeInstance->IsUnspecializedType())) &&
(!mIsComptimeModule))
{
// Don't keep instructions for unspecialized types
mBfIRBuilder->Func_DeleteBody(mCurMethodInstance->mIRFunction);
@ -20712,7 +20726,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
// We don't want to hold on to pointers to LLVMFunctions of unspecialized types.
// This allows us to delete the mScratchModule LLVM module without rebuilding all
// unspecialized types
if ((mCurTypeInstance->IsUnspecializedType()) || (mCurTypeInstance->IsInterface()))
if (((mCurTypeInstance->IsUnspecializedType()) && (!mIsComptimeModule)) ||
(mCurTypeInstance->IsInterface()))
{
BfLogSysM("ProcessMethod Clearing IRFunction: %p\n", methodInstance);
methodInstance->mIRFunction = BfIRFunction();
@ -21904,7 +21919,8 @@ void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& man
if (!methodInstance->mIRFunction)
{
BfIRFunction func;
bool wantsLLVMFunc = ((!typeInstance->IsUnspecializedType()) && (!methodDef->IsEmptyPartial())) && (funcType);
bool wantsLLVMFunc = ((!typeInstance->IsUnspecializedType() || (mIsComptimeModule)) &&
(!methodDef->IsEmptyPartial())) && (funcType);
/*if (mCurTypeInstance->mTypeDef->mName->ToString() == "ClassA")
{
@ -22042,6 +22058,79 @@ static void StackOverflow()
StackOverflow();
}
void BfModule::StartMethodDeclaration(BfMethodInstance* methodInstance, BfMethodState* prevMethodState)
{
methodInstance->mHasStartedDeclaration = true;
auto methodDef = methodInstance->mMethodDef;
auto typeInstance = methodInstance->GetOwner();
bool hasNonGenericParams = false;
bool hasGenericParams = false;
int dependentGenericStartIdx = 0;
if (methodDef->mIsLocalMethod)
{
// If we're a local generic method inside an outer generic method, we can still be considered unspecialized
// if our outer method's generic args are specialized but ours are unspecialized. This is because locals get
// instantiated uniquely for each specialized or unspecialized pass through the outer method, but the local
// method still 'inherits' the outer's generic arguments -- but we still need to make an unspecialized pass
// over the local method each time
auto rootMethodInstance = prevMethodState->GetRootMethodState()->mMethodInstance;
dependentGenericStartIdx = 0;
if (rootMethodInstance != NULL)
{
if (rootMethodInstance->mMethodInfoEx != NULL)
dependentGenericStartIdx = (int)rootMethodInstance->mMethodInfoEx->mMethodGenericArguments.size();
methodInstance->mIsUnspecialized = rootMethodInstance->mIsUnspecialized;
methodInstance->mIsUnspecializedVariation = rootMethodInstance->mIsUnspecializedVariation;
}
}
for (int genericArgIdx = dependentGenericStartIdx; genericArgIdx < (int)methodInstance->GetNumGenericArguments(); genericArgIdx++)
{
auto genericArgType = methodInstance->mMethodInfoEx->mMethodGenericArguments[genericArgIdx];
if (genericArgType->IsGenericParam())
{
hasGenericParams = true;
auto genericParam = (BfGenericParamType*)genericArgType;
methodInstance->mIsUnspecialized = true;
if ((genericParam->mGenericParamKind != BfGenericParamKind_Method) || (genericParam->mGenericParamIdx != genericArgIdx))
methodInstance->mIsUnspecializedVariation = true;
}
else
{
hasNonGenericParams = true;
if (genericArgType->IsUnspecializedType())
{
methodInstance->mIsUnspecialized = true;
methodInstance->mIsUnspecializedVariation = true;
}
}
}
if ((hasGenericParams) && (hasNonGenericParams))
{
methodInstance->mIsUnspecializedVariation = true;
}
if (typeInstance->IsUnspecializedType())
{
// A specialized method within an unspecialized type is considered an unspecialized variation -- in the sense that we don't
// actually want to do method processing on it
if ((!methodInstance->mIsUnspecialized) && (methodInstance->GetNumGenericArguments() != 0))
methodInstance->mIsUnspecializedVariation = true;
methodInstance->mIsUnspecialized = true;
}
if (methodInstance->mIsUnspecializedVariation)
BF_ASSERT(methodInstance->mIsUnspecialized);
if (methodDef->mMethodType == BfMethodType_Mixin)
methodInstance->mIsUnspecialized = true;
}
// methodDeclaration is NULL for default constructors
void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList)
{
@ -22064,7 +22153,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
BfMethodState methodState;
SetAndRestoreValue<BfMethodState*> prevMethodState(mCurMethodState, &methodState);
methodState.mTempKind = BfMethodState::TempKind_Static;
defer({ mCurMethodInstance->mHasBeenDeclared = true; });
// If we are doing this then we may end up creating methods when var types are unknown still, failing on splat/zero-sized info
@ -22101,92 +22190,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
if ((methodInstance->IsSpecializedByAutoCompleteMethod()) || (mCurTypeInstance->IsFunction()))
addToWorkList = false;
bool hasNonGenericParams = false;
bool hasGenericParams = false;
int dependentGenericStartIdx = 0;
if (methodDef->mIsLocalMethod)
{
// If we're a local generic method inside an outer generic method, we can still be considered unspecialized
// if our outer method's generic args are specialized but ours are unspecialized. This is because locals get
// instantiated uniquely for each specialized or unspecialized pass through the outer method, but the local
// method still 'inherits' the outer's generic arguments -- but we still need to make an unspecialized pass
// over the local method each time
auto rootMethodInstance = prevMethodState.mPrevVal->GetRootMethodState()->mMethodInstance;
dependentGenericStartIdx = 0;
if (rootMethodInstance != NULL)
{
if (rootMethodInstance->mMethodInfoEx != NULL)
dependentGenericStartIdx = (int)rootMethodInstance->mMethodInfoEx->mMethodGenericArguments.size();
methodInstance->mIsUnspecialized = rootMethodInstance->mIsUnspecialized;
methodInstance->mIsUnspecializedVariation = rootMethodInstance->mIsUnspecializedVariation;
}
}
for (int genericArgIdx = dependentGenericStartIdx; genericArgIdx < (int) methodInstance->GetNumGenericArguments(); genericArgIdx++)
{
auto genericArgType = methodInstance->mMethodInfoEx->mMethodGenericArguments[genericArgIdx];
if (genericArgType->IsGenericParam())
{
hasGenericParams = true;
auto genericParam = (BfGenericParamType*)genericArgType;
methodInstance->mIsUnspecialized = true;
if ((genericParam->mGenericParamKind != BfGenericParamKind_Method) || (genericParam->mGenericParamIdx != genericArgIdx))
methodInstance->mIsUnspecializedVariation = true;
}
else
{
hasNonGenericParams = true;
if (genericArgType->IsUnspecializedType())
{
methodInstance->mIsUnspecialized = true;
methodInstance->mIsUnspecializedVariation = true;
}
}
}
if ((hasGenericParams) && (hasNonGenericParams))
{
methodInstance->mIsUnspecializedVariation = true;
}
if (typeInstance->IsUnspecializedType())
{
// A specialized method within an unspecialized type is considered an unspecialized variation -- in the sense that we don't
// actually want to do method processing on it
if ((!methodInstance->mIsUnspecialized) && (methodInstance->GetNumGenericArguments() != 0))
methodInstance->mIsUnspecializedVariation = true;
methodInstance->mIsUnspecialized = true;
}
//methodInstance->mIsUnspecializedVariation |= typeInstance->IsUnspecializedTypeVariation();
for (auto genericParamDef : methodDef->mGenericParams)
{
if (mCompiler->IsAutocomplete())
{
auto autoComplete = mCompiler->mResolvePassData->mAutoComplete;
//autoComplete->CheckTypeRef()
}
}
if (methodInstance->mIsUnspecializedVariation)
{
}
if (methodInstance->mIsUnspecializedVariation)
BF_ASSERT(methodInstance->mIsUnspecialized);
if (methodDef->mMethodType == BfMethodType_Mixin)
methodInstance->mIsUnspecialized = true;
if (methodInstance->mIsUnspecialized)
{
//BF_ASSERT(methodInstance->mDeclModule == methodInstance->GetOwner()->mModule);
}
if (!methodInstance->mHasStartedDeclaration)
StartMethodDeclaration(methodInstance, prevMethodState.mPrevVal);
BfAutoComplete* bfAutocomplete = NULL;
if (mCompiler->mResolvePassData != NULL)
@ -23164,7 +23170,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
// Don't compare specialized generic methods against normal methods
if ((((mCurMethodInstance->mIsUnspecialized) || (mCurMethodInstance->mMethodDef->mGenericParams.size() == 0))) &&
(!methodDef->mIsLocalMethod))
(!methodDef->mIsLocalMethod) && (!mCurTypeInstance->IsUnspecializedTypeVariation()))
{
if ((!methodInstance->mIsForeignMethodDef) && (methodDef->mMethodType != BfMethodType_Init))
{

View file

@ -1888,6 +1888,7 @@ public:
void GetMethodCustomAttributes(BfMethodInstance* methodInstance);
void SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& mangledName, bool isTemporaryFunc, bool* outIsIntrinsic);
void CheckHotMethod(BfMethodInstance* methodInstance, const StringImpl& mangledName);
void StartMethodDeclaration(BfMethodInstance* methodInstance, BfMethodState* prevMethodState);
void DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList = true);
void AddMethodToWorkList(BfMethodInstance* methodInstance);
bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
@ -1916,7 +1917,7 @@ public:
void AddHotDataReferences(BfHotDataReferenceBuilder* builder);
void ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfType* thisType, bool wantsDIData, SizedArrayImpl<BfIRMDNode>* diParams);
void ProcessMethod_ProcessDeferredLocals(int startIdx = 0);
void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false);
void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false, bool forceIRWrites = false);
void CreateDynamicCastMethod();
void CreateValueTypeEqualsMethod(bool strictEquals);
BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false);

View file

@ -4178,13 +4178,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
}
}
}
bool tryCE = true;
if (typeInstance->IsUnspecializedType())
tryCE = false;
if ((typeInstance->mDefineState == BfTypeDefineState_CETypeInit) && (tryCE))
if (typeInstance->mDefineState == BfTypeDefineState_CETypeInit)
{
if (populateType <= BfPopulateType_AllowStaticMethods)
return;
@ -12296,6 +12291,9 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
}
else if (constant->mConstType == BfConstType_Undef)
{
if (mIsComptimeModule)
return mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(toType));
BF_ASSERT(mBfIRBuilder->mIgnoreWrites);
auto undefConst = (BfConstantUndef*)constant;

View file

@ -843,6 +843,7 @@ public:
bool mIsUnspecialized:1;
bool mIsUnspecializedVariation:1;
bool mIsReified:1;
bool mHasStartedDeclaration:1;
bool mHasBeenDeclared:1;
bool mHasBeenProcessed:1;
bool mHasFailed:1;
@ -885,6 +886,7 @@ public:
mIsUnspecialized = false;
mIsUnspecializedVariation = false;
mIsReified = true;
mHasStartedDeclaration = false;
mHasBeenDeclared = false;
mHasBeenProcessed = false;
mHasFailed = false;
@ -2640,7 +2642,7 @@ public:
static String TypeToString(BfAstNode* typeRef);
static String TypeToString(BfTypeDef* typeDef, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None);
static bool TypeToString(StringImpl& str, BfTypeDef* typeDef, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None);
static bool TypeEquals(BfType* typeA, BfType* typeB, BfType* selfType);
static bool TypeEquals(BfType* typeA, BfType* typeB, BfTypeInstance* selfType);
template <typename T>
static void GetProjectList(BfType* checkType, T* projectList, int immutableLength)

View file

@ -187,6 +187,7 @@ enum BfTypeFlags
BfTypeFlags_Delegate = 0x20000,
BfTypeFlags_Function = 0x40000,
BfTypeFlags_HasDestructor = 0x80000,
BfTypeFlags_GenericParam = 0x100000
};
enum BfMethodFlags

View file

@ -912,6 +912,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme
return result;
}
break;
case BeUndefConstant::TypeId:
case BeConstant::TypeId:
{
uint64 u64Val = 0;
@ -1181,7 +1182,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme
// if (callInst->mInlineResult != NULL)
// return GetOperand(callInst->mInlineResult);
}
break;
break;
}
CeOperand* operandPtr = NULL;
@ -1279,7 +1280,7 @@ void CeBuilder::HandleParams()
}
}
void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance)
void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance, bool forceIRWrites)
{
SetAndRestoreValue<BfMethodState*> prevMethodStateInConstEval(mCeMachine->mCeModule->mCurMethodState, NULL);
BfAutoComplete* prevAutoComplete = NULL;
@ -1299,7 +1300,7 @@ void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance
mCeMachine->mCeModule->mHadBuildError = false;
auto irState = irBuilder->GetState();
auto beState = irCodeGen->GetState();
mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true);
mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true, forceIRWrites);
irCodeGen->SetState(beState);
irBuilder->SetState(irState);
@ -1322,27 +1323,27 @@ void CeBuilder::Build()
BfMethodInstance dupMethodInstance;
dupMethodInstance.CopyFrom(methodInstance);
auto methodDef = methodInstance->mMethodDef;
bool isGenericVariation = (methodInstance->mIsUnspecializedVariation) || (methodInstance->GetOwner()->IsUnspecializedTypeVariation());
int dependentGenericStartIdx = 0;
if ((((methodInstance->mMethodInfoEx != NULL) && ((int)methodInstance->mMethodInfoEx->mMethodGenericArguments.size() > dependentGenericStartIdx)) ||
((methodInstance->GetOwner()->IsGenericTypeInstance()) && (!isGenericVariation) && (!methodInstance->mMethodDef->mIsLocalMethod))))
((methodInstance->GetOwner()->IsGenericTypeInstance()) && (!isGenericVariation) && (!methodInstance->mMethodDef->mIsLocalMethod) && (!methodInstance->mIsUnspecialized))))
{
auto unspecializedMethodInstance = mCeMachine->mCeModule->GetUnspecializedMethodInstance(methodInstance, !methodInstance->mMethodDef->mIsLocalMethod);
if (!unspecializedMethodInstance->mHasBeenProcessed)
{
BfMethodInstance dupUnspecMethodInstance;
dupUnspecMethodInstance.CopyFrom(unspecializedMethodInstance);
ProcessMethod(unspecializedMethodInstance, &dupUnspecMethodInstance);
ProcessMethod(unspecializedMethodInstance, &dupUnspecMethodInstance, false);
dupMethodInstance.GetMethodInfoEx()->mGenericTypeBindings = dupUnspecMethodInstance.mMethodInfoEx->mGenericTypeBindings;
}
}
// Clear this so we can properly get QueueStaticField calls
mCeMachine->mCeModule->mStaticFieldRefs.Clear();
int startFunctionCount = (int)beModule->mFunctions.size();
ProcessMethod(methodInstance, &dupMethodInstance);
ProcessMethod(methodInstance, &dupMethodInstance, true);
if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized)
return;

View file

@ -730,7 +730,7 @@ public:
void EmitBinaryOp(CeOp iOp, CeOp fOp, const CeOperand& lhs, const CeOperand& rhs, CeOperand& result);
void EmitUnaryOp(CeOp iOp, CeOp fOp, const CeOperand& val, CeOperand& result);
void EmitSizedOp(CeOp op, const CeOperand& operand, CeOperand* result, bool allowNonStdSize);
void ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance);
void ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance, bool forceIRWrites);
void Build();
};

View file

@ -8167,8 +8167,8 @@ void DbgExprEvaluator::Visit(BfTypeAttrExpression* typeAttrExpr)
case BfToken_StrideOf:
mResult.mInt64 = dbgType->GetStride();
break;
case BfToken_TypeOf:
//TODO:
default:
Fail("Invalid attribute expression", typeAttrExpr);
break;
}
}

View file

@ -1,4 +1,7 @@
#pragma warning disable 168
using System;
using System.Diagnostics;
using System.Reflection;
namespace Tests
{
@ -317,17 +320,75 @@ namespace Tests
interface IParsable
{
public enum Error
{
case Unknown;
case Syntax(int pos);
case InvalidValue;
case UnexpectedEnd;
}
static Self GetDefault(Self[] arr);
static Result<Self> Parse(StringView sv, Self defaultVal);
static Result<Self, Error> ParseEx(StringView str)
{
Self[] arr = null;
Self defVal = GetDefault(arr);
switch (Parse(str, default(Self)))
{
case .Ok(let val): return .Ok(val);
case .Err: return .Err(.Unknown);
}
}
}
class ClassH : IParsable
{
static Self IParsable.GetDefault(ClassH[] arr)
{
return default;
}
public static Result<Self> Parse(StringView sv, ClassH defaultVal)
{
return .Err;
}
}
[AttributeUsage(.Method)]
struct MethodTestAttribute : Attribute, IComptimeMethodApply
{
public static String gLog = new .() ~ delete _;
[Comptime]
public void ApplyToMethod(ComptimeMethodInfo method)
{
Compiler.EmitMethodEntry(method, "int b = 2;");
}
}
struct Test4<T>
{
[Comptime, OnCompile(.TypeInit)]
public static void Generator()
{
T val = default;
Compiler.EmitTypeBody(typeof(Self), "int test = 0;");
}
[MethodTest]
public void Zank<T2>()
{
int c = b;
}
public void Test() mut
{
test = 1;
}
}
[Test]
public static void TestDefaults()
{
@ -367,6 +428,8 @@ namespace Tests
TestIFaceD(cg);
Test.Assert(cg.mA == 999);
Test.Assert(TestIFaceD2(cg) == 999);
ClassH ch = scope .();
}
}
}