1
0
Fork 0
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:
Brian Fiete 2022-01-20 08:18:28 -05:00
parent 3c091be0d5
commit a10ad8d6fe
5 changed files with 233 additions and 64 deletions

View file

@ -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))

View file

@ -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);

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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);
} }
} }
} }