mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 20:12:21 +02:00
Improved comptime var, undef, unspecialized variation
This commit is contained in:
parent
3c091be0d5
commit
a10ad8d6fe
5 changed files with 233 additions and 64 deletions
|
@ -5632,10 +5632,6 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
|
||||||
{
|
{
|
||||||
mModule->Fail("Const evaluation not allowed with cascade operator", targetSrc);
|
mModule->Fail("Const evaluation not allowed with cascade operator", targetSrc);
|
||||||
}
|
}
|
||||||
else if (methodInstance->mIsUnspecialized)
|
|
||||||
{
|
|
||||||
doConstReturn = true;
|
|
||||||
}
|
|
||||||
else if (((methodInstance->mComptimeFlags & BfComptimeFlag_OnlyFromComptime) != 0) && (!mModule->mIsComptimeModule))
|
else if (((methodInstance->mComptimeFlags & BfComptimeFlag_OnlyFromComptime) != 0) && (!mModule->mIsComptimeModule))
|
||||||
{
|
{
|
||||||
// This either generated an error already or this is just the non-const type check pass for a comptime-only method
|
// This either generated an error already or this is just the non-const type check pass for a comptime-only method
|
||||||
|
@ -5655,21 +5651,6 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
|
||||||
// This could only really be the case for a Type, since no other 'this' could qualify as const
|
// This could only really be the case for a Type, since no other 'this' could qualify as const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
bool hasUndef = false;
|
|
||||||
for (auto arg : irArgs)
|
|
||||||
{
|
|
||||||
auto constant = mModule->mBfIRBuilder->GetConstant(arg);
|
|
||||||
if (constant == NULL)
|
|
||||||
continue;
|
|
||||||
if (constant->mConstType == BfConstType_Undef)
|
|
||||||
{
|
|
||||||
hasUndef = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasUndef)
|
|
||||||
{
|
{
|
||||||
CeEvalFlags evalFlags = CeEvalFlags_None;
|
CeEvalFlags evalFlags = CeEvalFlags_None;
|
||||||
if ((mBfEvalExprFlags & BfEvalExprFlags_NoCeRebuildFlags) != 0)
|
if ((mBfEvalExprFlags & BfEvalExprFlags_NoCeRebuildFlags) != 0)
|
||||||
|
@ -5690,7 +5671,6 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
|
||||||
mModule->DeferRebuildType(mModule->mCurTypeInstance);
|
mModule->DeferRebuildType(mModule->mCurTypeInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
doConstReturn = true;
|
doConstReturn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10519,6 +10499,10 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr)
|
||||||
{
|
{
|
||||||
type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity);
|
type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity);
|
||||||
}
|
}
|
||||||
|
else if ((typeOfExpr->mTypeRef != NULL) && (typeOfExpr->mTypeRef->IsA<BfVarTypeReference>()))
|
||||||
|
{
|
||||||
|
type = mModule->GetPrimitiveType(BfTypeCode_Var);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowGlobalsSelf);
|
type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowGlobalsSelf);
|
||||||
|
@ -19602,6 +19586,12 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mExpectingType->IsVar())
|
||||||
|
{
|
||||||
|
mResult = mModule->GetDefaultTypedValue(mExpectingType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (expectingTypeInst == NULL)
|
if (expectingTypeInst == NULL)
|
||||||
{
|
{
|
||||||
if (mModule->PreFail())
|
if (mModule->PreFail())
|
||||||
|
@ -19609,12 +19599,6 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExpectingType->IsVar())
|
|
||||||
{
|
|
||||||
mResult = mModule->GetDefaultTypedValue(mExpectingType);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BfTypedValue expectingVal(expectingTypeInst);
|
BfTypedValue expectingVal(expectingTypeInst);
|
||||||
mResult = LookupField(memberRefExpr->mMemberName, expectingVal, findName);
|
mResult = LookupField(memberRefExpr->mMemberName, expectingVal, findName);
|
||||||
if ((mResult) || (mPropDef != NULL))
|
if ((mResult) || (mPropDef != NULL))
|
||||||
|
|
|
@ -3619,7 +3619,7 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
|
||||||
|
|
||||||
void BfModule::AddDependency(BfGenericParamInstance* genericParam, BfTypeInstance* usingType)
|
void BfModule::AddDependency(BfGenericParamInstance* genericParam, BfTypeInstance* usingType)
|
||||||
{
|
{
|
||||||
if (!genericParam->mExternType->IsGenericParam())
|
if ((genericParam->mExternType != NULL) && (!genericParam->mExternType->IsGenericParam()))
|
||||||
AddDependency(genericParam->mExternType, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint);
|
AddDependency(genericParam->mExternType, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint);
|
||||||
for (auto constraintTypeInst : genericParam->mInterfaceConstraints)
|
for (auto constraintTypeInst : genericParam->mInterfaceConstraints)
|
||||||
AddDependency(constraintTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint);
|
AddDependency(constraintTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint);
|
||||||
|
@ -18718,7 +18718,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
|
||||||
if (!methodInstance->mIsReified)
|
if (!methodInstance->mIsReified)
|
||||||
BF_ASSERT(!mIsReified);
|
BF_ASSERT(!mIsReified);
|
||||||
|
|
||||||
BF_ASSERT(!methodInstance->GetOwner()->IsUnspecializedTypeVariation());
|
BF_ASSERT((!methodInstance->GetOwner()->IsUnspecializedTypeVariation()) || (mIsComptimeModule));
|
||||||
|
|
||||||
if (methodInstance->mMethodInfoEx != NULL)
|
if (methodInstance->mMethodInfoEx != NULL)
|
||||||
{
|
{
|
||||||
|
@ -19060,7 +19060,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
|
||||||
methodState.mGenericTypeBindings = &methodInstance->GetMethodInfoEx()->mGenericTypeBindings;
|
methodState.mGenericTypeBindings = &methodInstance->GetMethodInfoEx()->mGenericTypeBindings;
|
||||||
}
|
}
|
||||||
else if ((((methodInstance->mMethodInfoEx != NULL) && ((int)methodInstance->mMethodInfoEx->mMethodGenericArguments.size() > dependentGenericStartIdx)) ||
|
else if ((((methodInstance->mMethodInfoEx != NULL) && ((int)methodInstance->mMethodInfoEx->mMethodGenericArguments.size() > dependentGenericStartIdx)) ||
|
||||||
((mCurTypeInstance->IsGenericTypeInstance()) && (!isGenericVariation) && (!methodInstance->mMethodDef->mIsLocalMethod) && (!methodInstance->mMethodDef->mDeclaringType->IsEmitted()))))
|
((mCurTypeInstance->IsGenericTypeInstance()) && (!isGenericVariation || mIsComptimeModule) && (!methodInstance->mMethodDef->mIsLocalMethod) && (!methodInstance->mMethodDef->mDeclaringType->IsEmitted()))))
|
||||||
{
|
{
|
||||||
unspecializedMethodInstance = GetUnspecializedMethodInstance(methodInstance, !methodInstance->mMethodDef->mIsLocalMethod);
|
unspecializedMethodInstance = GetUnspecializedMethodInstance(methodInstance, !methodInstance->mMethodDef->mIsLocalMethod);
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,12 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
|
||||||
}
|
}
|
||||||
|
|
||||||
auto typeDef = genericTypeInst->mTypeDef;
|
auto typeDef = genericTypeInst->mTypeDef;
|
||||||
for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
|
|
||||||
|
int startGenericParamIdx = 0;
|
||||||
|
if (typeDef->mOuterType != NULL)
|
||||||
|
startGenericParamIdx = typeDef->mOuterType->mGenericParamDefs.mSize + typeDef->mOuterType->mExternalConstraints.mSize;
|
||||||
|
|
||||||
|
for (int paramIdx = startGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
|
||||||
{
|
{
|
||||||
auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx];
|
auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx];
|
||||||
|
|
||||||
|
@ -3196,7 +3201,11 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
auto baseType = ResolveTypeRef(baseTypeRef, BfPopulateType_Declaration);
|
auto baseType = ResolveTypeRef(baseTypeRef, BfPopulateType_Declaration);
|
||||||
if (baseType != NULL)
|
if (baseType != NULL)
|
||||||
{
|
{
|
||||||
if (baseType->IsPrimitiveType())
|
if (baseType->IsVar())
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
else if (baseType->IsPrimitiveType())
|
||||||
{
|
{
|
||||||
underlyingType = baseType;
|
underlyingType = baseType;
|
||||||
}
|
}
|
||||||
|
@ -3438,6 +3447,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkType->IsVar())
|
||||||
|
{
|
||||||
|
// This can't explicitly be specified, but can occur from comptime
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (checkType->IsInterface())
|
if (checkType->IsInterface())
|
||||||
{
|
{
|
||||||
auto ifaceInst = checkType->ToTypeInstance();
|
auto ifaceInst = checkType->ToTypeInstance();
|
||||||
|
@ -5769,7 +5784,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
||||||
{
|
{
|
||||||
if (matchedMethod == NULL)
|
if (matchedMethod == NULL)
|
||||||
{
|
{
|
||||||
AssertErrorState();
|
// Assert on base type?
|
||||||
|
//AssertErrorState();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -9403,6 +9419,14 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod
|
||||||
genericParamResult = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[genericParamIdx];
|
genericParamResult = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[genericParamIdx];
|
||||||
genericTypeConstraint = genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx]->mTypeConstraint;
|
genericTypeConstraint = genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx]->mTypeConstraint;
|
||||||
|
|
||||||
|
if (contextTypeInstance != genericCheckTypeInstance)
|
||||||
|
{
|
||||||
|
// Don't allow an 'unspecialized variation' generic param
|
||||||
|
auto checkResult = contextTypeInstance->mGenericTypeInfo->mTypeGenericArguments[genericParamIdx];
|
||||||
|
if (!checkResult->IsGenericParam())
|
||||||
|
genericParamResult = checkResult;
|
||||||
|
}
|
||||||
|
|
||||||
HandleTypeGenericParamRef(identifierNode, genericTypeInst->mTypeDef, genericParamIdx);
|
HandleTypeGenericParamRef(identifierNode, genericTypeInst->mTypeDef, genericParamIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9410,18 +9434,30 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod
|
||||||
|
|
||||||
if ((contextMethodInstance != NULL) && (genericParamResult == NULL))
|
if ((contextMethodInstance != NULL) && (genericParamResult == NULL))
|
||||||
{
|
{
|
||||||
for (int genericParamIdx = (int)contextMethodInstance->mMethodDef->mGenericParams.size() - 1; genericParamIdx >= 0; genericParamIdx--)
|
auto checkMethodInstance = contextMethodInstance;
|
||||||
|
if (checkMethodInstance->mIsUnspecializedVariation)
|
||||||
|
checkMethodInstance = GetUnspecializedMethodInstance(checkMethodInstance);
|
||||||
|
|
||||||
|
for (int genericParamIdx = (int)checkMethodInstance->mMethodDef->mGenericParams.size() - 1; genericParamIdx >= 0; genericParamIdx--)
|
||||||
{
|
{
|
||||||
auto checkGenericParamDef = contextMethodInstance->mMethodDef->mGenericParams[genericParamIdx];
|
auto checkGenericParamDef = checkMethodInstance->mMethodDef->mGenericParams[genericParamIdx];
|
||||||
String genericName = checkGenericParamDef->mName;
|
String genericName = checkGenericParamDef->mName;
|
||||||
if (genericName == findName)
|
if (genericName == findName)
|
||||||
{
|
{
|
||||||
genericParamDef = checkGenericParamDef;
|
genericParamDef = checkGenericParamDef;
|
||||||
origGenericParamDef = checkGenericParamDef;
|
origGenericParamDef = checkGenericParamDef;
|
||||||
genericParamResult = contextMethodInstance->mMethodInfoEx->mMethodGenericArguments[genericParamIdx];
|
genericParamResult = checkMethodInstance->mMethodInfoEx->mMethodGenericArguments[genericParamIdx];
|
||||||
genericTypeConstraint = contextMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]->mTypeConstraint;
|
genericTypeConstraint = checkMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]->mTypeConstraint;
|
||||||
|
|
||||||
HandleMethodGenericParamRef(identifierNode, contextMethodInstance->GetOwner()->mTypeDef, contextMethodInstance->mMethodDef, genericParamIdx);
|
if (contextMethodInstance != checkMethodInstance)
|
||||||
|
{
|
||||||
|
// Don't allow an 'unspecialized variation' generic param
|
||||||
|
auto checkResult = contextMethodInstance->mMethodInfoEx->mMethodGenericArguments[genericParamIdx];
|
||||||
|
if (!checkResult->IsGenericParam())
|
||||||
|
genericParamResult = checkResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleMethodGenericParamRef(identifierNode, contextMethodInstance->GetOwner()->mTypeDef, checkMethodInstance->mMethodDef, genericParamIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10804,10 +10840,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
|
||||||
auto typeDef = mCompiler->mNullableTypeDef;
|
auto typeDef = mCompiler->mNullableTypeDef;
|
||||||
|
|
||||||
auto elementType = ResolveTypeRef(elementTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
auto elementType = ResolveTypeRef(elementTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
||||||
if (elementType == NULL)
|
if ((elementType == NULL) || (elementType->IsVar()))
|
||||||
{
|
{
|
||||||
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
||||||
return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
|
return ResolveTypeResult(typeRef, elementType, populateType, resolveFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypeInstance* genericTypeInst = new BfTypeInstance();
|
BfTypeInstance* genericTypeInst = new BfTypeInstance();
|
||||||
|
@ -10837,15 +10873,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
|
||||||
else if (auto pointerTypeRef = BfNodeDynCast<BfPointerTypeRef>(typeRef))
|
else if (auto pointerTypeRef = BfNodeDynCast<BfPointerTypeRef>(typeRef))
|
||||||
{
|
{
|
||||||
BfPointerType* pointerType = new BfPointerType();
|
BfPointerType* pointerType = new BfPointerType();
|
||||||
pointerType->mElementType = ResolveTypeRef(pointerTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
auto elementType = ResolveTypeRef(pointerTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
||||||
pointerType->mContext = mContext;
|
if ((elementType == NULL) || (elementType->IsVar()))
|
||||||
if (pointerType->mElementType == NULL)
|
|
||||||
{
|
{
|
||||||
delete pointerType;
|
delete pointerType;
|
||||||
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
||||||
return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
|
return ResolveTypeResult(typeRef, elementType, populateType, resolveFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pointerType->mElementType = elementType;
|
||||||
|
pointerType->mContext = mContext;
|
||||||
resolvedEntry->mValue = pointerType;
|
resolvedEntry->mValue = pointerType;
|
||||||
|
|
||||||
//int hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx);
|
//int hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx);
|
||||||
|
@ -10866,14 +10903,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
|
||||||
refType->mRefKind = BfRefType::RefKind_Out;
|
refType->mRefKind = BfRefType::RefKind_Out;
|
||||||
else if (refTypeRef->mRefToken->GetToken() == BfToken_Mut)
|
else if (refTypeRef->mRefToken->GetToken() == BfToken_Mut)
|
||||||
refType->mRefKind = BfRefType::RefKind_Mut;
|
refType->mRefKind = BfRefType::RefKind_Mut;
|
||||||
refType->mElementType = ResolveTypeRef(refTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
auto elementType = ResolveTypeRef(refTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
|
||||||
if (refType->mElementType == NULL)
|
if ((elementType == NULL) || (elementType->IsVar()))
|
||||||
{
|
{
|
||||||
delete refType;
|
delete refType;
|
||||||
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
|
||||||
return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
|
return ResolveTypeResult(typeRef, elementType, populateType, resolveFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refType->mElementType = elementType;
|
||||||
resolvedEntry->mValue = refType;
|
resolvedEntry->mValue = refType;
|
||||||
BF_ASSERT(BfResolvedTypeSet::Hash(refType, &lookupCtx) == resolvedEntry->mHash);
|
BF_ASSERT(BfResolvedTypeSet::Hash(refType, &lookupCtx) == resolvedEntry->mHash);
|
||||||
populateModule->InitType(refType, populateType);
|
populateModule->InitType(refType, populateType);
|
||||||
|
|
|
@ -3461,7 +3461,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
|
||||||
if (type->IsSizedArray())
|
if (type->IsSizedArray())
|
||||||
{
|
{
|
||||||
auto sizedArrayType = (BfSizedArrayType*)type;
|
auto sizedArrayType = (BfSizedArrayType*)type;
|
||||||
for (int i = 0; i < sizedArrayType->mSize; i++)
|
for (int i = 0; i < sizedArrayType->mElementCount; i++)
|
||||||
{
|
{
|
||||||
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
|
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
|
||||||
if (fieldConstant == NULL)
|
if (fieldConstant == NULL)
|
||||||
|
@ -3559,6 +3559,12 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (constant->mConstType == BfConstType_Undef)
|
||||||
|
{
|
||||||
|
memset(mMemory.mVals + addr, 0, type->mSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (constant->mConstType == BfConstType_AggCE)
|
if (constant->mConstType == BfConstType_AggCE)
|
||||||
{
|
{
|
||||||
auto constAggData = (BfConstantAggCE*)constant;
|
auto constAggData = (BfConstantAggCE*)constant;
|
||||||
|
@ -4130,8 +4136,8 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
|
||||||
{
|
{
|
||||||
args[argIdx] = module->CreateTypeDataRef(module->GetPrimitiveType(BfTypeCode_None));
|
args[argIdx] = module->CreateTypeDataRef(module->GetPrimitiveType(BfTypeCode_None));
|
||||||
}
|
}
|
||||||
else
|
// else
|
||||||
isConst = false;
|
// isConst = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ namespace Tests
|
||||||
if (cFieldCount == 0)
|
if (cFieldCount == 0)
|
||||||
return default(decltype(cMembers));
|
return default(decltype(cMembers));
|
||||||
|
|
||||||
|
#unwarn
|
||||||
decltype(cMembers) fields = ?;
|
decltype(cMembers) fields = ?;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -278,6 +279,132 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Yes;
|
||||||
|
struct No;
|
||||||
|
|
||||||
|
struct IsDictionary<T>
|
||||||
|
{
|
||||||
|
public typealias Result = comptype(_isDict(typeof(T)));
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private static Type _isDict(Type type)
|
||||||
|
{
|
||||||
|
if (let refType = type as SpecializedGenericType && refType.UnspecializedType == typeof(Dictionary<,>))
|
||||||
|
return typeof(Yes);
|
||||||
|
return typeof(No);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GetArg<T, C>
|
||||||
|
where C : const int
|
||||||
|
{
|
||||||
|
public typealias Result = comptype(_getArg(typeof(T), C));
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private static Type _getArg(Type type, int argIdx)
|
||||||
|
{
|
||||||
|
if (let refType = type as SpecializedGenericType)
|
||||||
|
return refType.GetGenericArg(argIdx);
|
||||||
|
return typeof(void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DictWrapper<T> where T : var
|
||||||
|
{
|
||||||
|
private T mValue = new .() ~ delete _;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DictWrapper<T>
|
||||||
|
where T : var
|
||||||
|
where IsDictionary<T>.Result : Yes
|
||||||
|
{
|
||||||
|
typealias TKey = GetArg<T, const 0>.Result;
|
||||||
|
typealias TValue = GetArg<T, const 1>.Result;
|
||||||
|
typealias KeyValuePair = (TKey key, TValue value);
|
||||||
|
typealias KeyRefValuePair = (TKey key, TValue* valueRef);
|
||||||
|
|
||||||
|
public ValueEnumerator GetValueEnumerator()
|
||||||
|
{
|
||||||
|
return ValueEnumerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ValueEnumerator : IRefEnumerator<TValue*>, IEnumerator<TValue>, IResettable
|
||||||
|
{
|
||||||
|
private SelfOuter mParent;
|
||||||
|
private int_cosize mIndex;
|
||||||
|
private TValue mCurrent;
|
||||||
|
|
||||||
|
const int_cosize cDictEntry = 1;
|
||||||
|
const int_cosize cKeyValuePair = 2;
|
||||||
|
|
||||||
|
public this(SelfOuter parent)
|
||||||
|
{
|
||||||
|
mParent = parent;
|
||||||
|
mIndex = 0;
|
||||||
|
mCurrent = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext() mut
|
||||||
|
{
|
||||||
|
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||||
|
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||||
|
while ((uint)mIndex < (uint)mParent.[Friend]mValue.[Friend]mCount)
|
||||||
|
{
|
||||||
|
if (mParent.[Friend]mValue.[Friend]mEntries[mIndex].mHashCode >= 0)
|
||||||
|
{
|
||||||
|
mCurrent = mParent.[Friend]mValue.[Friend]mEntries[mIndex].mValue;
|
||||||
|
mIndex++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIndex = mParent.[Friend]mValue.[Friend]mCount + 1;
|
||||||
|
mCurrent = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue Current
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
get { return mCurrent; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref TValue CurrentRef
|
||||||
|
{
|
||||||
|
get mut { return ref mCurrent; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref TKey Key
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ref mParent.[Friend]mValue.[Friend]mEntries[mIndex].mKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset() mut
|
||||||
|
{
|
||||||
|
mIndex = 0;
|
||||||
|
mCurrent = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<TValue> GetNext() mut
|
||||||
|
{
|
||||||
|
if (!MoveNext())
|
||||||
|
return .Err;
|
||||||
|
return Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<TValue*> GetNextRef() mut
|
||||||
|
{
|
||||||
|
if (!MoveNext())
|
||||||
|
return .Err;
|
||||||
|
return &CurrentRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public static void TestBasics()
|
public static void TestBasics()
|
||||||
{
|
{
|
||||||
|
@ -327,6 +454,20 @@ namespace Tests
|
||||||
ClassB<const 3>.TA f = default;
|
ClassB<const 3>.TA f = default;
|
||||||
Test.Assert(typeof(decltype(f)) == typeof(float));
|
Test.Assert(typeof(decltype(f)) == typeof(float));
|
||||||
Test.Assert(ClassB<const 3>.cTimesTen == 30);
|
Test.Assert(ClassB<const 3>.cTimesTen == 30);
|
||||||
|
|
||||||
|
DictWrapper<Dictionary<int, float>> dictWrap = scope .();
|
||||||
|
dictWrap.[Friend]mValue.Add(1, 2.3f);
|
||||||
|
dictWrap.[Friend]mValue.Add(2, 3.4f);
|
||||||
|
int idx = 0;
|
||||||
|
for (var value in dictWrap.GetValueEnumerator())
|
||||||
|
{
|
||||||
|
if (idx == 0)
|
||||||
|
Test.Assert(value == 2.3f);
|
||||||
|
else
|
||||||
|
Test.Assert(value == 3.4f);
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
Test.Assert(idx == 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue