diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ecca4d3d..5296bfa3 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5632,10 +5632,6 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* { 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)) { // This either generated an error already or this is just the non-const type check pass for a comptime-only method @@ -5656,41 +5652,25 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* } else { - bool hasUndef = false; - for (auto arg : irArgs) + CeEvalFlags evalFlags = CeEvalFlags_None; + if ((mBfEvalExprFlags & BfEvalExprFlags_NoCeRebuildFlags) != 0) + evalFlags = (CeEvalFlags)(evalFlags | CeEvalFlags_NoRebuild); + auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); + if (constRet) { - auto constant = mModule->mBfIRBuilder->GetConstant(arg); - if (constant == NULL) - continue; - if (constant->mConstType == BfConstType_Undef) - { - hasUndef = true; - break; - } + auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); + BF_ASSERT(!constRet.mType->IsVar()); + return constRet; } - if (!hasUndef) + if (mModule->mCompiler->mFastFinish) { - CeEvalFlags evalFlags = CeEvalFlags_None; - if ((mBfEvalExprFlags & BfEvalExprFlags_NoCeRebuildFlags) != 0) - evalFlags = (CeEvalFlags)(evalFlags | CeEvalFlags_NoRebuild); - auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); - if (constRet) + if ((mModule->mCurMethodInstance == NULL) || (!mModule->mCurMethodInstance->mIsAutocompleteMethod)) { - auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); - BF_ASSERT(!constRet.mType->IsVar()); - return constRet; + // We didn't properly resolve this so queue for a rebuild later + mModule->DeferRebuildType(mModule->mCurTypeInstance); } - - if (mModule->mCompiler->mFastFinish) - { - if ((mModule->mCurMethodInstance == NULL) || (!mModule->mCurMethodInstance->mIsAutocompleteMethod)) - { - // We didn't properly resolve this so queue for a rebuild later - mModule->DeferRebuildType(mModule->mCurTypeInstance); - } - } - } + } doConstReturn = true; } } @@ -10519,6 +10499,10 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr) { type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity); } + else if ((typeOfExpr->mTypeRef != NULL) && (typeOfExpr->mTypeRef->IsA())) + { + type = mModule->GetPrimitiveType(BfTypeCode_Var); + } else { type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowGlobalsSelf); @@ -19602,19 +19586,19 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx return; } + if (mExpectingType->IsVar()) + { + mResult = mModule->GetDefaultTypedValue(mExpectingType); + return; + } + if (expectingTypeInst == NULL) { if (mModule->PreFail()) mModule->Fail(StrFormat("Unqualified dot syntax cannot be used with type '%s'", mModule->TypeToString(mExpectingType).c_str()), nameRefNode); return; } - - if (mExpectingType->IsVar()) - { - mResult = mModule->GetDefaultTypedValue(mExpectingType); - return; - } - + BfTypedValue expectingVal(expectingTypeInst); mResult = LookupField(memberRefExpr->mMemberName, expectingVal, findName); if ((mResult) || (mPropDef != NULL)) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 715c273e..a42af100 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3619,7 +3619,7 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap 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); for (auto constraintTypeInst : genericParam->mInterfaceConstraints) AddDependency(constraintTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint); @@ -18718,7 +18718,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, if (!methodInstance->mIsReified) BF_ASSERT(!mIsReified); - BF_ASSERT(!methodInstance->GetOwner()->IsUnspecializedTypeVariation()); + BF_ASSERT((!methodInstance->GetOwner()->IsUnspecializedTypeVariation()) || (mIsComptimeModule)); if (methodInstance->mMethodInfoEx != NULL) { @@ -19060,7 +19060,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, methodState.mGenericTypeBindings = &methodInstance->GetMethodInfoEx()->mGenericTypeBindings; } 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); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 11abd130..c52ef9cb 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -339,9 +339,14 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan if (genericArg != NULL) genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericArg->mGenericTypeInfo->mMaxGenericDepth + 1); } - + 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]; @@ -3196,7 +3201,11 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy auto baseType = ResolveTypeRef(baseTypeRef, BfPopulateType_Declaration); if (baseType != NULL) { - if (baseType->IsPrimitiveType()) + if (baseType->IsVar()) + { + // Ignore + } + else if (baseType->IsPrimitiveType()) { underlyingType = baseType; } @@ -3438,6 +3447,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy continue; } + if (checkType->IsVar()) + { + // This can't explicitly be specified, but can occur from comptime + continue; + } + if (checkType->IsInterface()) { auto ifaceInst = checkType->ToTypeInstance(); @@ -5769,7 +5784,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) { if (matchedMethod == NULL) { - AssertErrorState(); + // Assert on base type? + //AssertErrorState(); } else { @@ -9403,6 +9419,14 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod genericParamResult = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[genericParamIdx]; 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); } } @@ -9410,18 +9434,30 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod 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; if (genericName == findName) { genericParamDef = checkGenericParamDef; origGenericParamDef = checkGenericParamDef; - genericParamResult = contextMethodInstance->mMethodInfoEx->mMethodGenericArguments[genericParamIdx]; - genericTypeConstraint = contextMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]->mTypeConstraint; + genericParamResult = checkMethodInstance->mMethodInfoEx->mMethodGenericArguments[genericParamIdx]; + 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 elementType = ResolveTypeRef(elementTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); - if (elementType == NULL) + if ((elementType == NULL) || (elementType->IsVar())) { mContext->mResolvedTypes.RemoveEntry(resolvedEntry); - return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); + return ResolveTypeResult(typeRef, elementType, populateType, resolveFlags); } BfTypeInstance* genericTypeInst = new BfTypeInstance(); @@ -10837,15 +10873,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula else if (auto pointerTypeRef = BfNodeDynCast(typeRef)) { BfPointerType* pointerType = new BfPointerType(); - pointerType->mElementType = ResolveTypeRef(pointerTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); - pointerType->mContext = mContext; - if (pointerType->mElementType == NULL) + auto elementType = ResolveTypeRef(pointerTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); + if ((elementType == NULL) || (elementType->IsVar())) { delete pointerType; 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; //int hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx); @@ -10866,14 +10903,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula refType->mRefKind = BfRefType::RefKind_Out; else if (refTypeRef->mRefToken->GetToken() == BfToken_Mut) refType->mRefKind = BfRefType::RefKind_Mut; - refType->mElementType = ResolveTypeRef(refTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); - if (refType->mElementType == NULL) + auto elementType = ResolveTypeRef(refTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); + if ((elementType == NULL) || (elementType->IsVar())) { delete refType; mContext->mResolvedTypes.RemoveEntry(resolvedEntry); - return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); + return ResolveTypeResult(typeRef, elementType, populateType, resolveFlags); } + refType->mElementType = elementType; resolvedEntry->mValue = refType; BF_ASSERT(BfResolvedTypeSet::Hash(refType, &lookupCtx) == resolvedEntry->mHash); populateModule->InitType(refType, populateType); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index c945ca4d..5dedd090 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -3461,7 +3461,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta if (type->IsSizedArray()) { 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]); if (fieldConstant == NULL) @@ -3559,6 +3559,12 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta return true; } + if (constant->mConstType == BfConstType_Undef) + { + memset(mMemory.mVals + addr, 0, type->mSize); + return true; + } + if (constant->mConstType == BfConstType_AggCE) { auto constAggData = (BfConstantAggCE*)constant; @@ -4130,8 +4136,8 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns { args[argIdx] = module->CreateTypeDataRef(module->GetPrimitiveType(BfTypeCode_None)); } - else - isConst = false; +// else +// isConst = false; } } diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index b93197c5..2405f6d9 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -145,6 +145,7 @@ namespace Tests if (cFieldCount == 0) return default(decltype(cMembers)); +#unwarn decltype(cMembers) fields = ?; int i = 0; @@ -278,6 +279,132 @@ namespace Tests } } + struct Yes; + struct No; + + struct IsDictionary + { + 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 + 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 where T : var + { + private T mValue = new .() ~ delete _; + } + + extension DictWrapper + where T : var + where IsDictionary.Result : Yes + { + typealias TKey = GetArg.Result; + typealias TValue = GetArg.Result; + typealias KeyValuePair = (TKey key, TValue value); + typealias KeyRefValuePair = (TKey key, TValue* valueRef); + + public ValueEnumerator GetValueEnumerator() + { + return ValueEnumerator(this); + } + + public struct ValueEnumerator : IRefEnumerator, IEnumerator, 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 GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + + public Result GetNextRef() mut + { + if (!MoveNext()) + return .Err; + return &CurrentRef; + } + } + } + [Test] public static void TestBasics() { @@ -327,6 +454,20 @@ namespace Tests ClassB.TA f = default; Test.Assert(typeof(decltype(f)) == typeof(float)); Test.Assert(ClassB.cTimesTen == 30); + + DictWrapper> 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); } } }