diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 33b32e7d..b3257506 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4288,7 +4288,7 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef) BfRefType* refType = (BfRefType*)varDecl->mResolvedType; BfType* innerType = refType->mElementType; - if (innerType->IsValuelessType()) + if (innerType->IsValuelessNonOpaqueType()) { if (refType->mRefKind == BfRefType::RefKind_Mut) return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), innerType, BfTypedValueKind_MutableValue); @@ -4314,7 +4314,7 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef) else localResult = BfTypedValue(varDecl->mAddr, varDecl->mResolvedType, varDecl->mIsReadOnly ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr); } - else if (varDecl->mResolvedType->IsValuelessType()) + else if (varDecl->mResolvedType->IsValuelessNonOpaqueType()) { if ((varDecl->mResolvedType->IsRef()) && (!allowRef)) { @@ -7309,7 +7309,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl& ir argVal = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType); } - if (argVal.mType->IsValuelessType()) + if (argVal.mType->IsValuelessNonOpaqueType()) return; bool wantSplat = false; if ((argVal.mType->IsSplattable()) && (!disableSplat) && (!IsComptime())) @@ -7404,7 +7404,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl& ir void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMethodInstance* methodInstance, SizedArrayImpl& irArgs, bool skipMutCheck) { - MakeBaseConcrete(argVal); + MakeBaseConcrete(argVal); auto methodDef = methodInstance->mMethodDef; if (methodInstance->IsSkipCall()) @@ -7456,14 +7456,14 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth } } - if (argVal.mType->IsValuelessType()) + if (argVal.mType->IsValuelessNonOpaqueType()) return; auto owner = methodInstance->GetOwner(); bool allowThisSplatting; if (mModule->mIsComptimeModule) - allowThisSplatting = owner->IsTypedPrimitive() || owner->IsValuelessType(); + allowThisSplatting = owner->IsTypedPrimitive() || owner->IsValuelessNonOpaqueType(); else allowThisSplatting = methodInstance->AllowsSplatting(-1); @@ -21057,7 +21057,11 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool } else { - if (ptr.mType->IsValuelessType()) + if (ptr.mType->IsOpaque()) + { + mModule->Fail(StrFormat("Unable to assign to opaque type '%s'", mModule->TypeToString(ptr.mType).c_str()), assignExpr); + } + else if (ptr.mType->IsValuelessType()) { mModule->EmitEnsureInstructionAt(); } @@ -22577,7 +22581,11 @@ void BfExprEvaluator::HandleIndexerExpression(BfIndexerExpression* indexerExpr, auto underlyingType = pointerType->mElementType; mModule->mBfIRBuilder->PopulateType(underlyingType); - if (isUndefIndex) + if (underlyingType->IsOpaque()) + { + mModule->Fail(StrFormat("Unable to index opaque pointer type '%s'", mModule->TypeToString(pointerType).c_str()), indexerExpr); + } + else if (isUndefIndex) { mResult = mModule->GetDefaultTypedValue(underlyingType, false, BfDefaultValueKind_Addr); } @@ -23014,7 +23022,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, mModule->FixIntUnknown(mResult); mModule->PopulateType(mResult.mType); auto ptrType = mModule->CreatePointerType(mResult.mType); - if (mResult.mType->IsValuelessType()) + if ((mResult.mType->IsValuelessType()) && (!mResult.mType->IsOpaque())) { if (!mModule->IsInSpecializedSection()) { @@ -23072,7 +23080,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfPointerType* pointerType = (BfPointerType*)derefTarget.mType; auto resolvedType = pointerType->mElementType; mModule->PopulateType(resolvedType); - if (resolvedType->IsValuelessType()) + if (resolvedType->IsValuelessNonOpaqueType()) mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), resolvedType, true); else mResult = BfTypedValue(derefTarget.mValue, resolvedType, true); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 00c8e212..7049dd0f 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2794,7 +2794,7 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine) { BfPointerType* pointerType = (BfPointerType*)type; populateModule->PopulateType(pointerType->mElementType, BfPopulateType_Data); - if (pointerType->mElementType->IsValuelessType()) + if (pointerType->mElementType->IsValuelessNonOpaqueType()) { irType = GetPrimitiveType(BfTypeCode_NullPtr); } @@ -2813,7 +2813,7 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine) { BfRefType* refType = (BfRefType*)type; - if (refType->mElementType->IsValuelessType()) + if (refType->mElementType->IsValuelessNonOpaqueType()) irType = GetPrimitiveType(BfTypeCode_NullPtr); else { diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index fc515055..9640d050 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -13205,7 +13205,7 @@ BfTypedValue BfModule::ToRef(BfTypedValue typedValue, BfRefType* refType) if (refType->mRefKind == BfRefType::RefKind_Mut) refType = CreateRefType(typedValue.mType); - if (!typedValue.mType->IsValuelessType()) + if (!typedValue.mType->IsValuelessNonOpaqueType()) typedValue = MakeAddressable(typedValue, false, true); return BfTypedValue(typedValue.mValue, refType); } @@ -13216,7 +13216,7 @@ BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bo return typedValue; PopulateType(typedValue.mType); - if ((typedValue.mType->IsValuelessType()) || (typedValue.mType->IsVar())) + if ((typedValue.mType->IsValuelessNonOpaqueType()) || (typedValue.mType->IsVar())) return BfTypedValue(mBfIRBuilder->GetFakeVal(), typedValue.mType, false); if (typedValue.mValue.IsConst()) @@ -13518,7 +13518,7 @@ BfTypedValue BfModule::MakeAddressable(BfTypedValue typedVal, bool forceMutable, if ((forceAddressable) || ((typedVal.mType->IsValueType()) && - (!typedVal.mType->IsValuelessType()))) + (!typedVal.mType->IsValuelessNonOpaqueType()))) { wasReadOnly = true; // Any non-addr is implicitly read-only @@ -21175,7 +21175,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, for ( ; argIdx < irParamCount; localIdx++) { bool isThis = ((localIdx == 0) && (!mCurMethodInstance->mMethodDef->mIsStatic)); - if ((isThis) && (thisType->IsValuelessType())) + if ((isThis) && (thisType->IsValuelessNonOpaqueType())) isThis = false; if ((!mIsComptimeModule) && (methodInstance->GetStructRetIdx() == argIdx)) @@ -21192,7 +21192,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, paramVar = methodState.mLocals[localIdx]; if ((paramVar->mCompositeCount == -1) && (!paramVar->mIsConst) && - ((!paramVar->mResolvedType->IsValuelessType()) || (paramVar->mResolvedType->IsMethodRef()))) + ((!paramVar->mResolvedType->IsValuelessNonOpaqueType()) || (paramVar->mResolvedType->IsMethodRef()))) break; localIdx++; } @@ -21358,7 +21358,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, continue; bool isThis = ((curLocalIdx == 0) && (!mCurMethodInstance->mMethodDef->mIsStatic)); - if ((isThis) && (thisType->IsValuelessType())) + if ((isThis) && (thisType->IsValuelessNonOpaqueType())) isThis = false; if (paramVar->mValue.IsArg()) @@ -21423,7 +21423,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, } } - if (paramVar->mResolvedType->IsValuelessType()) + if (paramVar->mResolvedType->IsValuelessNonOpaqueType()) { diVariable = mBfIRBuilder->DbgCreateAutoVariable(diFunction, paramName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, diType); @@ -21691,7 +21691,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, if (loweredTypeCode2 != BfTypeCode_None) argIdx++; } - else if (!paramVar->mResolvedType->IsValuelessType()) + else if (!paramVar->mResolvedType->IsValuelessNonOpaqueType()) { argIdx++; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 8598025c..8d2bf531 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1090,8 +1090,8 @@ bool BfMethodInstance::HasThis() if (mMethodDef->mIsStatic) return false; if ((mMethodInfoEx != NULL) && (mMethodInfoEx->mClosureInstanceInfo != NULL) && (mMethodInfoEx->mClosureInstanceInfo->mThisOverride != NULL)) - return !mMethodInfoEx->mClosureInstanceInfo->mThisOverride->IsValuelessType(); - return (!mMethodInstanceGroup->mOwner->IsValuelessType()); + return !mMethodInfoEx->mClosureInstanceInfo->mThisOverride->IsValuelessNonOpaqueType(); + return (!mMethodInstanceGroup->mOwner->IsValuelessNonOpaqueType()); } bool BfMethodInstance::IsVirtual() @@ -1278,7 +1278,7 @@ bool BfMethodInstance::IsParamSkipped(int paramIdx) BfType* paramType = GetParamType(paramIdx); if ((paramType->CanBeValuelessType()) && (paramType->IsDataIncomplete())) resolveModule->PopulateType(paramType, BfPopulateType_Data); - if ((paramType->IsValuelessType()) && (!paramType->IsMethodRef())) + if ((paramType->IsValuelessNonOpaqueType()) && (!paramType->IsMethodRef())) return true; return false; } @@ -1378,6 +1378,11 @@ int BfMethodInstance::DbgGetVirtualMethodNum() void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, SizedArrayImpl& paramTypes, bool forceStatic) { + if (mMethodDef->mName == "Test4") + { + NOP; + } + BfModule* resolveModule = module->mContext->mUnreifiedModule; resolveModule->PopulateType(mReturnType); @@ -1498,7 +1503,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, if (checkType->CanBeValuelessType()) resolveModule->PopulateType(checkType, BfPopulateType_Data); - if ((checkType->IsValuelessType()) && (!checkType->IsMethodRef())) + if ((checkType->IsValuelessNonOpaqueType()) && (!checkType->IsMethodRef())) continue; if ((doSplat) && (!checkType->IsMethodRef())) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 6aca5bb7..525aefaf 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -560,6 +560,7 @@ public: virtual bool IsVoidPtr() { return false; } virtual bool CanBeValuelessType() { return false; } virtual bool IsValuelessType() { BF_ASSERT(mSize != -1); BF_ASSERT(mDefineState >= BfTypeDefineState_Defined); return mSize == 0; } + virtual bool IsValuelessNonOpaqueType() { return IsValuelessType() && !IsOpaque(); } virtual bool IsSelf() { return false; } virtual bool IsDot() { return false; } virtual bool IsVar() { return false; } @@ -2537,7 +2538,7 @@ public: virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType(); } virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation(); } virtual bool CanBeValuelessType() override { return mElementType->CanBeValuelessType(); } - virtual bool IsValuelessType() override { return mElementType->IsValuelessType(); } + virtual bool IsValuelessType() override { return mElementType->IsValuelessNonOpaqueType(); } }; class BfArrayType : public BfTypeInstance diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index a3dee6ff..c7c0eb43 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -1905,7 +1905,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD localDef->mValue = initValue.mValue; if ((localDef->mAddr) && (!localDef->mResolvedType->IsValuelessType())) { - if (!initValue.mType->IsVar()) + if ((!initValue.mType->IsVar()) && (!initValue.mType->IsValuelessType())) wantsStore = true; } else diff --git a/IDEHelper/Tests/src/Opaques.bf b/IDEHelper/Tests/src/Opaques.bf new file mode 100644 index 00000000..885aac88 --- /dev/null +++ b/IDEHelper/Tests/src/Opaques.bf @@ -0,0 +1,32 @@ +using System; + +namespace Tests; + +class Opaques +{ + struct StructA + { + public int mA; + public int mB; + } + + struct StructB; + + public static void Modify(this ref StructB @this, int addA, int addB) + { + StructB* sbPtr = &@this; + StructA* saPtr = (.)(void*)sbPtr; + saPtr.mA += addA; + saPtr.mB += addB; + } + + [Test] + public static void TestBasics() + { + StructA sa = .() { mA = 123, mB = 234 }; + StructB* sb = (.)&sa; + sb.Modify(1000, 2000); + Test.Assert(sa.mA == 1123); + Test.Assert(sa.mB == 2234); + } +} \ No newline at end of file