diff --git a/IDEHelper/Backend/BeIRCodeGen.h b/IDEHelper/Backend/BeIRCodeGen.h index cc99faa6..3a2c3dfc 100644 --- a/IDEHelper/Backend/BeIRCodeGen.h +++ b/IDEHelper/Backend/BeIRCodeGen.h @@ -105,6 +105,7 @@ public: BeIRTypeEntry& GetTypeEntry(int typeId); void FixValues(BeStructType* structType, CmdParamVec& values); + void FixValues(BeStructType* structType, SizedArrayImpl& values); public: BeIRCodeGen(); diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 47f7b18f..e8945e2a 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -1085,6 +1085,9 @@ bool BfAstNode::Equals(const StringView& str) bool BfAstNode::Equals(const char* str) { + if (mSrcEnd == 0) + return false; + auto source = GetSourceData(); const char* ptrLhs = source->mSrc + mSrcStart; const char* ptrLhsEnd = source->mSrc + mSrcEnd; diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index ab5650fd..f0be3cc7 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -78,6 +78,12 @@ static bool CheckProtection(BfProtection protection, bool allowProtected, bool a struct BfVariant { + struct StructData + { + int mSize; + uint8 mData[1]; + }; + BfTypeCode mTypeCode; int mWarnType; union @@ -111,6 +117,63 @@ struct BfVariant mWarnType = 0; mUInt64 = 0; } + + BfVariant(const BfVariant& variant) + { + mTypeCode = BfTypeCode_None; + mWarnType = 0; + mUInt64 = 0; + *this = variant; + } + + BfVariant(BfVariant&& variant) + { + mTypeCode = variant.mTypeCode; + mWarnType = variant.mWarnType; + mUInt64 = variant.mUInt64; + variant.mTypeCode = BfTypeCode_None; + } + + ~BfVariant() + { + if (mTypeCode == BfTypeCode_Struct) + delete mPtr; + } + + BfVariant& operator=(const BfVariant& variant) + { + if (mTypeCode == BfTypeCode_Struct) + delete mPtr; + mTypeCode = variant.mTypeCode; + mWarnType = variant.mWarnType; + mUInt64 = variant.mUInt64; + + if (variant.mTypeCode == BfTypeCode_Struct) + { + StructData* srcStructData = (StructData*)mPtr; + StructData* destStructData = (StructData*)(new uint8[srcStructData->mSize + 4]); + destStructData->mSize = srcStructData->mSize; + memcpy(destStructData->mData, srcStructData->mData, destStructData->mSize); + mPtr = destStructData; + } + + return *this; + } + + bool operator==(const BfVariant& variant) const + { + if (mTypeCode != variant.mTypeCode) + return false; + if (mTypeCode == BfTypeCode_Struct) + { + StructData* structDataA = (StructData*)mPtr; + StructData* structDataB = (StructData*)variant.mPtr; + if (structDataA->mSize != structDataB->mSize) + return false; + return memcmp(structDataA->mData, structDataB->mData, structDataA->mSize) == 0; + } + return mUInt64 == variant.mUInt64; + } }; enum BfToken : uint8 @@ -3494,6 +3557,20 @@ BfUnaryOp BfTokenToUnaryOp(BfToken token); BfAssignmentOp BfTokenToAssignmentOp(BfToken token); bool BfIsCommentBlock(BfCommentKind commentKind); +template<> +struct BeefHash +{ + size_t operator()(const Beefy::BfVariant& val) const + { + if (val.mTypeCode == BfTypeCode_Struct) + { + BfVariant::StructData* structData = (Beefy::BfVariant::StructData*)val.mPtr; + return HashBytes(structData->mData, structData->mSize); + } + return (size_t)val.mUInt64; + } +}; + NS_BF_END namespace std diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 0bb1eacc..c2446b7e 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -987,7 +987,8 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild if (type->IsConstExprValue()) { auto constExprType = (BfConstExprValueType*)type; - if ((constExprType->mValue.mTypeCode != BfTypeCode_StringId) && (constExprType->mType->mSize != mScratchModule->GetPrimitiveType(constExprType->mValue.mTypeCode)->mSize)) + if ((constExprType->mValue.mTypeCode != BfTypeCode_StringId) && (constExprType->mValue.mTypeCode != BfTypeCode_Struct) && + (constExprType->mType->mSize != mScratchModule->GetPrimitiveType(constExprType->mValue.mTypeCode)->mSize)) wantDeleteType = true; } if (wantDeleteType) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 778a1f5d..43088168 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -3933,7 +3933,7 @@ bool BfExprEvaluator::IsVar(BfType* type, bool forceIgnoreWrites) return false; } -void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant) +void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant, BfType* type) { switch (variant.mTypeCode) { @@ -4036,6 +4036,13 @@ void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant) } mModule->Fail("Invalid undef literal", refNode); break; + case BfTypeCode_Struct: + if (type != NULL) + { + BfVariant::StructData* structData = (BfVariant::StructData*)variant.mPtr; + mResult = BfTypedValue(mModule->mBfIRBuilder->ReadConstant(structData->mData, type), type); + } + break; default: mModule->Fail("Invalid literal", refNode); break; @@ -12382,6 +12389,23 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr) if (autoComplete != NULL) autoComplete->CheckTypeRef(checkTypeExpr->mTypeRef, false, true); + auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); + + if (checkTypeExpr->mTypeRef->IsA()) + { + bool isVar = false; + if ((targetValue.mType != NULL) && (targetValue.mType->IsVar())) + { + auto irb = mModule->mBfIRBuilder; + BfIRValue boolResult = mModule->CreateAlloca(boolType); + irb->CreateAlignedStore(irb->CreateConst(BfTypeCode_Boolean, 1), boolResult, 1); + mResult = BfTypedValue(irb->CreateAlignedLoad(boolResult, 1), boolType); + } + else + mResult = BfTypedValue(mModule->GetConstValue(0, boolType), boolType); + return; + } + auto targetType = mModule->ResolveTypeRef(checkTypeExpr->mTypeRef, BfPopulateType_Declaration); if (!targetType) { @@ -12391,7 +12415,6 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr) mModule->AddDependency(targetType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); - auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); if (targetValue.mType->IsVar()) { mResult = mModule->GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Undef); @@ -12638,11 +12661,13 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) auto elementType = targetType->GetUnderlyingType(); if (elementType == targetValue.mType) { + mModule->mBfIRBuilder->PopulateType(targetType); + // We match nullable element auto allocaInst = mModule->CreateAlloca(targetType); - auto hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 1); // has_value + auto hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 2); // has_value mModule->mBfIRBuilder->CreateStore(mModule->GetConstValue(1, boolType), hasValueAddr); - hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 0); // value + hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 1); // value mModule->mBfIRBuilder->CreateStore(targetValue.mValue, hasValueAddr); mResult = BfTypedValue(allocaInst, targetType, true); _CheckResult(); diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 07c6add9..bcc4d71a 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -438,7 +438,7 @@ public: bool CheckForMethodName(BfAstNode* refNode, BfTypeInstance* typeInst, const StringImpl& findName); bool IsVar(BfType* type, bool forceIgnoreWrites = false); - void GetLiteral(BfAstNode* refNode, const BfVariant& variant); + void GetLiteral(BfAstNode* refNode, const BfVariant& variant, BfType* type = NULL); void FinishExpressionResult(); virtual bool CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode); BfAutoComplete* GetAutoComplete(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index fa847e62..b420e6cf 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -8149,7 +8149,11 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_DisallowComptime); // We we have a deferredResolveTypes then we defer the generic validation, because we may have a case like // `where T : Dictionay and TElem : IHashable` and we don't want to throw the error on `T` before we build `TElem` - auto constraintType = ResolveTypeRef(constraintTypeRef, (deferredResolveTypes != NULL) ? BfPopulateType_Identity : BfPopulateType_Declaration, resolveFlags); + BfType* constraintType; + if (constraintTypeRef->IsA()) + constraintType = GetPrimitiveType(BfTypeCode_Var); + else + constraintType = ResolveTypeRef(constraintTypeRef, (deferredResolveTypes != NULL) ? BfPopulateType_Identity : BfPopulateType_Declaration, resolveFlags); if (constraintType != NULL) { if (deferredResolveTypes != NULL) @@ -8176,6 +8180,12 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar if (constraintType->IsInstanceOf(mCompiler->mStringTypeDef)) isValidTypeCode = true; + if (constraintType->IsValueType()) + isValidTypeCode = true; + + if (constraintType->IsVar()) + isValidTypeCode = true; + switch (typeCode) { case BfTypeCode_StringId: @@ -8208,7 +8218,7 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar } else { - Fail("Const constraint must be a primitive type", constraintTypeRef); + Fail("Const constraint must be a valuetype or string", constraintTypeRef); } } else @@ -8572,7 +8582,8 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS // actual expression comparisons, but we are overly permissive now and then we may fail on specialization if ((constExprValueType->mValue.mTypeCode != primType->mTypeDef->mTypeCode) && (constExprValueType->mValue.mTypeCode != BfTypeCode_Let) && - (primType->mTypeDef->mTypeCode != BfTypeCode_Let)) + (primType->mTypeDef->mTypeCode != BfTypeCode_Let) && + (primType->mTypeDef->mTypeCode != BfTypeCode_Var)) { bool doError = true; @@ -12844,6 +12855,14 @@ BfVariant BfModule::TypedValueToVariant(BfAstNode* refNode, const BfTypedValue& } } } + else + { + BfVariant::StructData* structData = (BfVariant::StructData*)(new uint8[value.mType->mSize + 4]); + structData->mSize = value.mType->mSize; + mBfIRBuilder->WriteConstant(value.mValue, structData->mData, value.mType); + variant.mTypeCode = BfTypeCode_Struct; + variant.mPtr = structData; + } return variant; } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 3abb832f..cb7ad5c8 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1653,7 +1653,8 @@ public: BfIRValue GetStringObjectValue(int idx, bool define, bool force); BfIRValue GetStringObjectValue(const StringImpl& str, bool define = false, bool force = false); BfIRValue CreateGlobalConstValue(const StringImpl& name, BfIRValue constant, BfIRType type, bool external); - void VariantToString(StringImpl& str, const BfVariant& variant); + void DataToString(StringImpl& str, void* ptr, BfType* type); + void VariantToString(StringImpl& str, const BfVariant& variant, BfType* type = NULL); StringT<128> TypeToString(BfType* resolvedType, Array* genericMethodParamNameOverrides = NULL); StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array* genericMethodParamNameOverrides = NULL); void DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None, Array* genericMethodParamNameOverrides = NULL); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 8b056096..c6fb83a9 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -1495,9 +1495,13 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType if (resolvedTypeRef->IsConstExprValue()) { + BfConstExprValueType* constExprType = (BfConstExprValueType*)resolvedTypeRef; + resolvedTypeRef->mRevision = mRevision; resolvedTypeRef->mSize = 0; resolvedTypeRef->mAlign = 0; resolvedTypeRef->mDefineState = BfTypeDefineState_Defined; + if (constExprType->mType->IsTypeInstance()) + AddDependency(constExprType->mType, resolvedTypeRef, BfDependencyMap::DependencyFlag_TypeGenericArg); return; } @@ -7576,7 +7580,7 @@ BfConstExprValueType* BfModule::CreateConstExprValueType(const BfTypedValue& typ mContext->mConstExprValueTypePool.GiveBack(constExprValueType); if (resolvedConstExprValueType != NULL) - BF_ASSERT(resolvedConstExprValueType->mValue.mInt64 == constExprValueType->mValue.mInt64); + BF_ASSERT(resolvedConstExprValueType->mValue == constExprValueType->mValue); return resolvedConstExprValueType; } @@ -7599,7 +7603,7 @@ BfConstExprValueType* BfModule::CreateConstExprValueType(const BfVariant& varian mContext->mConstExprValueTypePool.GiveBack(constExprValueType); if (resolvedConstExprValueType != NULL) - BF_ASSERT(resolvedConstExprValueType->mValue.mInt64 == constExprValueType->mValue.mInt64); + BF_ASSERT(resolvedConstExprValueType->mValue == constExprValueType->mValue); return resolvedConstExprValueType; } @@ -10729,18 +10733,27 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod if (constType == NULL) constType = GetPrimitiveType(BfTypeCode_IntPtr); - BfExprEvaluator exprEvaluator(this); - exprEvaluator.mExpectingType = constType; - exprEvaluator.GetLiteral(identifierNode, constExprValueType->mValue); - - if (exprEvaluator.mResult) + if (constType->IsVar()) { - auto castedVal = CastToValue(identifierNode, exprEvaluator.mResult, constType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail)); - if (castedVal) - return BfTypedValue(castedVal, constType); + BfExprEvaluator exprEvaluator(this); + exprEvaluator.GetLiteral(identifierNode, constExprValueType->mValue, constExprValueType->mType); + return exprEvaluator.mResult; } + else + { + BfExprEvaluator exprEvaluator(this); + exprEvaluator.mExpectingType = constType; + exprEvaluator.GetLiteral(identifierNode, constExprValueType->mValue, constExprValueType->mType); - return exprEvaluator.mResult; + if (exprEvaluator.mResult) + { + auto castedVal = CastToValue(identifierNode, exprEvaluator.mResult, constType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail)); + if (castedVal) + return BfTypedValue(castedVal, constType); + } + + return exprEvaluator.mResult; + } } else if (genericParamResult->IsGenericParam()) { @@ -12031,7 +12044,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } if (!BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx)) { - BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx)); + BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx) || (mCompiler->mCanceling)); } BfLogSysM("Generic type %p typeHash: %8X\n", genericTypeInst, resolvedEntry->mHashCode); @@ -13259,9 +13272,15 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp BfTypedValue fromTypedValue; if (typedVal.mKind == BfTypedValueKind_GenericConstValue) - fromTypedValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint, false, BfDefaultValueKind_Undef); + { + if (genericParamInst->mTypeConstraint->IsVar()) + fromTypedValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint); + else + fromTypedValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint, false, BfDefaultValueKind_Undef); + } else fromTypedValue = BfTypedValue(mBfIRBuilder->GetFakeVal(), genericParamInst->mTypeConstraint, genericParamInst->mTypeConstraint->IsValueType()); + prevIgnoreWrites.Restore(); auto result = CastToValue(srcNode, fromTypedValue, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); if (result) @@ -13768,7 +13787,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp auto variantVal = TypedValueToVariant(srcNode, typedVal, true); if ((mBfIRBuilder->IsIntable(variantVal.mTypeCode)) && (mBfIRBuilder->IsIntable(toConstExprValueType->mValue.mTypeCode))) { - if (variantVal.mInt64 == toConstExprValueType->mValue.mInt64) + if (variantVal == toConstExprValueType->mValue) return typedVal.mValue; } else if ((mBfIRBuilder->IsFloat(variantVal.mTypeCode)) && (mBfIRBuilder->IsFloat(toConstExprValueType->mValue.mTypeCode))) @@ -15337,7 +15356,181 @@ StringT<128> BfModule::TypeToString(BfType* resolvedType, BfTypeNameFlags typeNa return str; } -void BfModule::VariantToString(StringImpl& str, const BfVariant& variant) +void BfModule::DataToString(StringImpl& str, void* ptr, BfType* type) +{ + if (type->IsPrimitiveType()) + { + BfPrimitiveType* primType = (BfPrimitiveType*)type; + BfTypeCode typeCode = primType->GetTypeCode(); + + if (typeCode == BfTypeCode_IntPtr) + { + if (mSystem->mPtrSize == 8) + typeCode = BfTypeCode_Int64; + else + typeCode = BfTypeCode_Int32; + } + else if (typeCode == BfTypeCode_UIntPtr) + { + if (mSystem->mPtrSize == 8) + typeCode = BfTypeCode_UInt64; + else + typeCode = BfTypeCode_UInt32; + } + + switch (typeCode) + { + case BfTypeCode_Boolean: + if (*(uint8*)ptr == 0) + str += "false"; + else if (*(uint8*)ptr == 1) + str += "true"; + else + str += StrFormat("%d", *(uint8*)ptr); + break; + case BfTypeCode_Int8: + str += StrFormat("%d", *(int8*)ptr); + break; + case BfTypeCode_UInt8: + str += StrFormat("%d", *(uint8*)ptr); + break; + case BfTypeCode_Int16: + str += StrFormat("%d", *(int16*)ptr); + break; + case BfTypeCode_UInt16: + str += StrFormat("%d", *(uint16*)ptr); + break; + case BfTypeCode_Int32: + str += StrFormat("%d", *(int32*)ptr); + break; + case BfTypeCode_Char8: + case BfTypeCode_Char16: + case BfTypeCode_Char32: + { + uint32 c = 0; + if (typeCode == BfTypeCode_Char8) + c = *(uint8*)ptr; + else if (typeCode == BfTypeCode_Char16) + c = *(uint16*)ptr; + else if (typeCode == BfTypeCode_Char32) + c = *(uint32*)ptr; + + if ((c >= 32) && (c <= 0x7E)) + str += StrFormat("'%c'", (char)c); + else if (c <= 0xFF) + str += StrFormat("'\\x%2X'", c); + else + str += StrFormat("'\\u{%X}'", c); + } + break; + case BfTypeCode_UInt32: + str += StrFormat("%lu", *(uint32*)ptr); + break; + case BfTypeCode_Int64: + str += StrFormat("%lld", *(int64*)ptr); + break; + case BfTypeCode_UInt64: + str += StrFormat("%llu", *(uint64*)ptr); + break; + case BfTypeCode_Float: + { + char cstr[64]; + ExactMinimalFloatToStr(*(float*)ptr, cstr); + str += cstr; + if (strchr(cstr, '.') == NULL) + str += ".0f"; + else + str += "f"; + } + break; + case BfTypeCode_Double: + { + char cstr[64]; + ExactMinimalDoubleToStr(*(double*)ptr, cstr); + str += cstr; + if (strchr(cstr, '.') == NULL) + str += ".0"; + } + break; + case BfTypeCode_StringId: + { + int stringId = *(int32*)ptr; + auto stringPoolEntry = mContext->mStringObjectIdMap[stringId]; + str += '"'; + str += SlashString(stringPoolEntry.mString, false, false, true); + str += '"'; + } + break; + case BfTypeCode_Let: + str += "?"; + break; + default: break; + } + } + else + { + if (type->IsInstanceOf(mCompiler->mClosedRangeTypeDef)) + { + if (type->mSize == 16) + str += StrFormat("%d...%d", ((int64*)ptr)[0], ((int64*)ptr)[1]); + else + str += StrFormat("%d...%d", ((int32*)ptr)[0], ((int32*)ptr)[1]); + return; + } + + if (type->IsInstanceOf(mCompiler->mRangeTypeDef)) + { + if (type->mSize == 16) + str += StrFormat("%d..<%d", ((int64*)ptr)[0], ((int64*)ptr)[1]); + else + str += StrFormat("%d..<%d", ((int32*)ptr)[0], ((int32*)ptr)[1]); + return; + } + + BfTypeInstance* typeInstance = type->ToTypeInstance(); + if (typeInstance != NULL) + { + str += "("; + DoPopulateType(typeInstance); + + int showIdx = 0; + + if ((typeInstance->mBaseType != NULL) && (!typeInstance->mBaseType->IsInstanceOf(mCompiler->mValueTypeTypeDef))) + { + DataToString(str, ptr, typeInstance->mBaseType); + showIdx++; + } + + for (auto& fieldInstance : typeInstance->mFieldInstances) + { + if (fieldInstance.mDataOffset >= 0) + { + if (showIdx > 0) + str += ", "; + DataToString(str, (uint8*)ptr + fieldInstance.mDataOffset, fieldInstance.mResolvedType); + showIdx++; + } + } + + str += ")"; + } + else if (type->IsPointer()) + str += "null"; + else + { + str += "uint8[]("; + for (int i = 0; i < type->mSize; i++) + { + if (i > 0) + str += ", "; + str += StrFormat("%d", ((uint8_t*)ptr)[i]); + } + str += ")"; + } + } +} + +void BfModule::VariantToString(StringImpl& str, const BfVariant& variant, BfType* type) { switch (variant.mTypeCode) { @@ -15407,6 +15600,24 @@ void BfModule::VariantToString(StringImpl& str, const BfVariant& variant) case BfTypeCode_Let: str += "?"; break; + case BfTypeCode_Struct: + { + BfVariant::StructData* structData = (BfVariant::StructData*)variant.mPtr; + if (type == NULL) + { + str += "uint8[]("; + for (int i = 0; i < structData->mSize; i++) + { + if (i > 0) + str += ", "; + str += StrFormat("%d", structData->mData[i]); + } + str += ")"; + break; + } + DataToString(str, structData->mData, type); + } + break; default: break; } } @@ -15991,11 +16202,16 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF { str += "const "; - DoTypeToString(str, constExprValueType->mType, typeNameFlags, genericMethodNameOverrides); - str += " "; + if ((!constExprValueType->mType->IsInstanceOf(mCompiler->mRangeTypeDef)) && + (!constExprValueType->mType->IsInstanceOf(mCompiler->mClosedRangeTypeDef))) + { + DoTypeToString(str, constExprValueType->mType, typeNameFlags, genericMethodNameOverrides); + if (constExprValueType->mValue.mTypeCode != BfTypeCode_Boolean) + str += " "; + } } - VariantToString(str, constExprValueType->mValue); + VariantToString(str, constExprValueType->mValue, constExprValueType->mType); return; } diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 15bcce99..365df273 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -899,6 +899,13 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int { isDone = true; + auto prevNode = mVisitorPos.Get(checkIdx + 1); + if (prevNode = BfNodeDynCast(prevNode)) + { + // Allow expressions like '3...' + isDone = false; + } + auto nextNode = mVisitorPos.Get(checkIdx + 1); if (auto nextToken = BfNodeDynCast(nextNode)) { @@ -906,6 +913,10 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int isDone = false; } } + else if ((checkToken == BfToken_Minus) && (chevronDepth > 0)) + { + // Allow - literal + } else if (checkToken != BfToken_LBracket) isDone = true; @@ -5341,14 +5352,20 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF bool doAddType = genericIdentifier != NULL; bool addAsExpr = false; - //if (mCompatMode) + if (BfNodeDynCast(nextNode) != NULL) { - if (BfNodeDynCast(nextNode) != NULL) + doAddType = true; + addAsExpr = true; + } + else if (auto tokenNode = BfNodeDynCast(nextNode)) + { + if (tokenNode->mToken == BfToken_Minus) { doAddType = true; addAsExpr = true; } } + if (genericIdentifier == NULL) { auto nextNode = mVisitorPos.GetNext(); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 7c099548..c4d67043 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -3100,6 +3100,12 @@ BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression* { outType = NULL; + BfMethodState methodState; + methodState.mTempKind = BfMethodState::TempKind_Static; + SetAndRestoreValue prevMethodState; + if (ctx->mModule->mCurMethodState == NULL) + prevMethodState.Init(ctx->mModule->mCurMethodState, &methodState); + BfConstResolver constResolver(ctx->mModule); BfVariant variant; constResolver.mBfEvalExprFlags = BfEvalExprFlags_NoCast; @@ -3303,7 +3309,8 @@ int BfResolvedTypeSet::DoHash(BfType* type, LookupContext* ctx, bool allowRef, i else if (type->IsConstExprValue()) { BfConstExprValueType* constExprValueType = (BfConstExprValueType*)type; - int hashVal = ((int)constExprValueType->mValue.mTypeCode << 17) ^ (constExprValueType->mValue.mInt32 << 3) ^ HASH_CONSTTYPE; + int32 dataHash = BeefHash()(constExprValueType->mValue); + int hashVal = ((int)constExprValueType->mValue.mTypeCode << 17) ^ (dataHash << 3) ^ HASH_CONSTTYPE; hashVal = ((hashVal ^ (Hash(constExprValueType->mType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal; return hashVal; } @@ -4078,7 +4085,8 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa return 0; } - auto hashVal = ((int)result.mTypeCode << 17) ^ (result.mInt32 << 3) ^ HASH_CONSTTYPE; + int32 dataHash = BeefHash()(result); + auto hashVal = ((int)result.mTypeCode << 17) ^ (dataHash << 3) ^ HASH_CONSTTYPE; hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal; return hashVal; } @@ -4331,7 +4339,7 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) BfConstExprValueType* rhsConstExprValueType = (BfConstExprValueType*)rhs; return (lhsConstExprValueType->mType == rhsConstExprValueType->mType) && - (lhsConstExprValueType->mValue.mInt64 == rhsConstExprValueType->mValue.mInt64); + (lhsConstExprValueType->mValue == rhsConstExprValueType->mValue); } else { @@ -5032,8 +5040,7 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* return false; } - return (result.mTypeCode == lhsConstExprType->mValue.mTypeCode) && - (result.mInt64 == lhsConstExprType->mValue.mInt64); + return result == lhsConstExprType->mValue; } else { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index c8dc53ab..d6e3f4df 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -2827,7 +2827,7 @@ public: // checkEntry->mType can be NULL if we're in the process of filling it in (and this Insert is from an element type) // OR if the type resolution failed after node insertion - if ((checkEntry->mValue != NULL) && (hashVal == checkEntry->mHashCode) && (Equals(checkEntry->mValue, findType, ctx))) + if ((checkEntry->mValue != NULL) && (hashVal == checkEntry->mHashCode) && (Equals(checkEntry->mValue, findType, ctx))) { *entryPtr = EntryRef(this, checkEntryIdx); return false; diff --git a/IDEHelper/Tests/src/ConstExprs.bf b/IDEHelper/Tests/src/ConstExprs.bf index 780e3742..0149d116 100644 --- a/IDEHelper/Tests/src/ConstExprs.bf +++ b/IDEHelper/Tests/src/ConstExprs.bf @@ -48,6 +48,43 @@ namespace Tests } } + struct TestRangedArray where TRange : const var + { + [OnCompile(.TypeInit), Comptime] + static void TypeInit() + { + if (TRange is var) + return; + + int rangeStart = 0; + int rangeEnd = 0; + + if (ClosedRange range = TRange as ClosedRange?) + { + rangeStart = range.Start; + rangeEnd = range.End+1; + } + else if (Range range = TRange as Range?) + { + rangeStart = range.Start; + rangeEnd = range.End; + } + else + { + Compiler.EmitTypeBody(typeof(Self), scope $""" + public const String cError = "Invalid type: {TRange}"; + """); + return; + } + + Compiler.EmitTypeBody(typeof(Self), scope $""" + public const int cRangeStart = {rangeStart}; + public const int cRangeEnd = {rangeEnd}; + public T[{rangeEnd-rangeStart}] mData; + """); + } + } + [Test] public static void TestBasics() { @@ -61,6 +98,9 @@ namespace Tests ClassC cc = scope .(); Test.Assert(cc.Test() == 1); + + Test.Assert(TestRangedArray.cRangeEnd - TestRangedArray.cRangeStart == 7); + Test.Assert(TestRangedArray.cError == "Invalid type: -3...^1"); } } }