From abeda6909b1d931fcb38505199a85d9b1562e30d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 17 Jun 2020 05:13:53 -0700 Subject: [PATCH] Added concept of strict equality --- BeefLibs/corlib/src/Collections/List.bf | 73 ++++++++++++++++--- BeefLibs/corlib/src/Span.bf | 16 +++++ IDE/src/Compiler/BfParser.bf | 4 +- IDEHelper/Compiler/BfAst.cpp | 23 ++++++ IDEHelper/Compiler/BfAst.h | 6 ++ IDEHelper/Compiler/BfDefBuilder.cpp | 13 ++++ IDEHelper/Compiler/BfExprEvaluator.cpp | 92 ++++++++++++++---------- IDEHelper/Compiler/BfModule.cpp | 40 ++++++----- IDEHelper/Compiler/BfModule.h | 4 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 3 +- IDEHelper/Compiler/BfParser.cpp | 26 +++++-- IDEHelper/Compiler/BfSystem.h | 1 + IDEHelper/DbgExprEvaluator.cpp | 27 ++++--- 13 files changed, 249 insertions(+), 79 deletions(-) diff --git a/BeefLibs/corlib/src/Collections/List.bf b/BeefLibs/corlib/src/Collections/List.bf index f9a3a1ed..a2ee132f 100644 --- a/BeefLibs/corlib/src/Collections/List.bf +++ b/BeefLibs/corlib/src/Collections/List.bf @@ -420,14 +420,6 @@ namespace System.Collections return -1; } - public int LastIndexOf(T item) - { - for (int i = mSize - 1; i >= 0; i--) - if (mItems[i] == item) - return i; - return -1; - } - public int IndexOf(T item, int index) { for (int i = index; i < mSize; i++) @@ -444,6 +436,46 @@ namespace System.Collections return -1; } + public int IndexOfStrict(T item) + { + for (int i = 0; i < mSize; i++) + if (mItems[i] === item) + return i; + return -1; + } + + public int IndexOfStrict(T item, int index) + { + for (int i = index; i < mSize; i++) + if (mItems[i] === item) + return i; + return -1; + } + + public int IndexOfStrict(T item, int index, int count) + { + for (int i = index; i < index + count; i++) + if (mItems[i] === item) + return i; + return -1; + } + + public int LastIndexOf(T item) + { + for (int i = mSize - 1; i >= 0; i--) + if (mItems[i] == item) + return i; + return -1; + } + + public int LastIndexOfStrict(T item) + { + for (int i = mSize - 1; i >= 0; i--) + if (mItems[i] === item) + return i; + return -1; + } + public void Insert(int index, T item) { var item; // This creates a copy - required if item is a ref to an element @@ -577,6 +609,31 @@ namespace System.Collections return false; } + public bool RemoveStrict(T item) + { + int index = IndexOfStrict(item); + if (index >= 0) + { + RemoveAt(index); + return true; + } + + return false; + } + + public Result GetAndRemove(T item) + { + int index = IndexOf(item); + if (index >= 0) + { + T val = mItems[index]; + RemoveAt(index); + return val; + } + + return .Err; + } + /// The method returns the index of the given value in the list. If the /// list does not contain the given value, the method returns a negative /// integer. The bitwise complement operator (~) can be applied to a diff --git a/BeefLibs/corlib/src/Span.bf b/BeefLibs/corlib/src/Span.bf index e88e4c2d..0b858785 100644 --- a/BeefLibs/corlib/src/Span.bf +++ b/BeefLibs/corlib/src/Span.bf @@ -147,6 +147,22 @@ namespace System mLength = 0; } + public int IndexOf(T item) + { + for (int i = 0; i < mLength; i++) + if (mPtr[i] == item) + return i; + return -1; + } + + public int IndexOfStrict(T item) + { + for (int i = 0; i < mLength; i++) + if (mPtr[i] === item) + return i; + return -1; + } + public void RemoveFromStart(int length) mut { Debug.Assert((uint)length <= (uint)mLength); diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 611ac727..b29abda0 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -328,8 +328,8 @@ namespace IDE.Compiler if (oldIdx <= expectedOldIdx) { #if DEBUG - Utils.WriteTextFile(@"c:\temp\old.txt", oldText); - Utils.WriteTextFile(@"c:\temp\new.txt", newText); + Utils.WriteTextFile(@"c:\temp\old.txt", oldText).IgnoreError(); + Utils.WriteTextFile(@"c:\temp\new.txt", newText).IgnoreError(); Debug.FatalError("Reformat failed"); #endif break; // Error - abort diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 81195c61..d6914842 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -1303,6 +1303,8 @@ const char* Beefy::BfTokenToString(BfToken token) return "mixin"; case BfToken_Mut: return "mut"; + case BfToken_NameOf: + return "nameof"; case BfToken_Namespace: return "namespace"; case BfToken_New: @@ -1385,8 +1387,12 @@ const char* Beefy::BfTokenToString(BfToken token) return "="; case BfToken_CompareEquals: return "=="; + case BfToken_CompareStrictEquals: + return "==="; case BfToken_CompareNotEquals: return "!="; + case BfToken_CompareStrictNotEquals: + return "!=="; case BfToken_LessEquals: return "<="; case BfToken_GreaterEquals: @@ -1559,7 +1565,9 @@ int Beefy::BfGetBinaryOpPrecendence(BfBinaryOp binOp) case BfBinaryOp_LessThanOrEqual: return 5; case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: return 4; case BfBinaryOp_ConditionalAnd: return 3; @@ -1590,7 +1598,9 @@ const char* Beefy::BfGetOpName(BfBinaryOp binOp) case BfBinaryOp_LeftShift: return "<<"; case BfBinaryOp_RightShift: return ">>"; case BfBinaryOp_Equality: return "=="; + case BfBinaryOp_StrictEquality: return "==="; case BfBinaryOp_InEquality: return "!="; + case BfBinaryOp_StrictInEquality: return "!=="; case BfBinaryOp_GreaterThan: return ">"; case BfBinaryOp_LessThan: return "<"; case BfBinaryOp_GreaterThanOrEqual: return ">="; @@ -1655,8 +1665,12 @@ BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token) return BfBinaryOp_RightShift; case BfToken_CompareEquals: return BfBinaryOp_Equality; + case BfToken_CompareStrictEquals: + return BfBinaryOp_StrictEquality; case BfToken_CompareNotEquals: return BfBinaryOp_InEquality; + case BfToken_CompareStrictNotEquals: + return BfBinaryOp_StrictInEquality; case BfToken_RChevron: return BfBinaryOp_GreaterThan; case BfToken_LChevron: @@ -1770,8 +1784,12 @@ BfBinaryOp Beefy::BfGetOppositeBinaryOp(BfBinaryOp origOp) { case BfBinaryOp_Equality: return BfBinaryOp_InEquality; + case BfBinaryOp_StrictEquality: + return BfBinaryOp_StrictInEquality; case BfBinaryOp_InEquality: return BfBinaryOp_Equality; + case BfBinaryOp_StrictInEquality: + return BfBinaryOp_StrictEquality; case BfBinaryOp_LessThan: return BfBinaryOp_GreaterThanOrEqual; case BfBinaryOp_LessThanOrEqual: @@ -1808,6 +1826,11 @@ BfBinaryOp Beefy::BfGetFlippedBinaryOp(BfBinaryOp origOp) return BfBinaryOp_None; } +bool Beefy::BfBinOpEqualityCheck(BfBinaryOp binOp) +{ + return (binOp >= BfBinaryOp_Equality) && (binOp <= BfBinaryOp_StrictInEquality); +} + bool Beefy::BfIsCommentBlock(BfCommentKind commentKind) { return diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index d50763de..3bbff37c 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -146,6 +146,7 @@ enum BfToken : uint8 BfToken_Let, BfToken_Mixin, BfToken_Mut, + BfToken_NameOf, BfToken_Namespace, BfToken_New, BfToken_Null, @@ -187,7 +188,9 @@ enum BfToken : uint8 BfToken_Yield, BfToken_AssignEquals, BfToken_CompareEquals, + BfToken_CompareStrictEquals, BfToken_CompareNotEquals, + BfToken_CompareStrictNotEquals, BfToken_LessEquals, BfToken_GreaterEquals, BfToken_Spaceship, @@ -1706,7 +1709,9 @@ enum BfBinaryOp BfBinaryOp_LeftShift, BfBinaryOp_RightShift, BfBinaryOp_Equality, + BfBinaryOp_StrictEquality, BfBinaryOp_InEquality, + BfBinaryOp_StrictInEquality, BfBinaryOp_GreaterThan, BfBinaryOp_LessThan, BfBinaryOp_GreaterThanOrEqual, @@ -3199,6 +3204,7 @@ bool BfTokenIsKeyword(BfToken token); BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp); BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp); BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp); +bool BfBinOpEqualityCheck(BfBinaryOp binOp); int BfGetBinaryOpPrecendence(BfBinaryOp binOp); const char* BfGetOpName(BfBinaryOp binOp); const char* BfGetOpName(BfUnaryOp unaryOp); diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 724454ee..31ea80e7 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -2061,6 +2061,19 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) AddParam(methodDef, mSystem->mDirectSelfTypeRef, "rhs"); } + if (needsEqualsMethod) + { + auto methodDef = new BfMethodDef(); + mCurTypeDef->mMethods.push_back(methodDef); + methodDef->mDeclaringType = mCurTypeDef; + methodDef->mName = BF_METHODNAME_DEFAULT_STRICT_EQUALS; + methodDef->mReturnTypeRef = mSystem->mDirectBoolTypeRef; + methodDef->mProtection = BfProtection_Private; + methodDef->mIsStatic = true; + AddParam(methodDef, mSystem->mDirectSelfTypeRef, "lhs"); + AddParam(methodDef, mSystem->mDirectSelfTypeRef, "rhs"); + } + HashContext inlineHashCtx; if (mCurSource != NULL) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ab08b8c8..663b9e06 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -18009,10 +18009,12 @@ bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken, switch (binaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: if (rightConst->mInt64 < minValue) constResult = 0; break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: if (rightConst->mInt64 < minValue) constResult = 1; break; @@ -18033,12 +18035,14 @@ bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken, switch (binaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: if (rightConst->mInt64 < minValue) constResult = 0; else if (rightConst->mInt64 > maxValue) constResult = 0; break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: if (rightConst->mInt64 < minValue) constResult = 1; else if (rightConst->mInt64 > maxValue) @@ -18332,7 +18336,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod }; // This case fixes cases like "c == 0" where "0" is technically an int but can be reduced - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if (BfBinOpEqualityCheck(binaryOp)) { if ((resultType != otherType) && (resultTypedValue->mValue.IsConst()) && (mModule->CanCast(*resultTypedValue, otherType))) { @@ -18351,9 +18355,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } - if ((otherType->IsNull()) && ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality))) + if ((otherType->IsNull()) && (BfBinOpEqualityCheck(binaryOp))) { - bool isEquality = (binaryOp == BfBinaryOp_Equality); + bool isEquality = (binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality); if ((resultType->IsValueType()) && (!resultType->IsFunction())) { @@ -18408,7 +18412,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } // Check for constant equality checks (mostly for strings) - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if (BfBinOpEqualityCheck(binaryOp)) { auto leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue); auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue); @@ -18423,7 +18427,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (rightStringPoolIdx != -1) { bool isEqual = leftStringPoolIdx == rightStringPoolIdx; - if (binaryOp == BfBinaryOp_InEquality) + if ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality)) isEqual = !isEqual; mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType); return; @@ -18434,7 +18438,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (eqResult != -1) { bool isEqual = eqResult == 1; - if (binaryOp == BfBinaryOp_InEquality) + if ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality)) isEqual = !isEqual; mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType); return; @@ -18447,7 +18451,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod { // As an optimization, we don't call user operator overloads for null checks bool skipOpOverload = false; - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if ((binaryOp == BfBinaryOp_StrictEquality) || (binaryOp == BfBinaryOp_StrictInEquality)) + skipOpOverload = true; + else if (BfBinOpEqualityCheck(binaryOp)) { auto leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue); auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue); @@ -18456,7 +18462,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod skipOpOverload = true; if ((rightConstant != NULL) && (rightConstant->IsNull())) skipOpOverload = true; - } + } if (!skipOpOverload) { @@ -18593,9 +18599,11 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod switch (useBinaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mResult.mValue, zeroVal), boolType); break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mResult.mValue, zeroVal), boolType); break; case BfBinaryOp_GreaterThan: @@ -18665,9 +18673,11 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod break; switch (findBinaryOp) - { + { case BfBinaryOp_Equality: - case BfBinaryOp_InEquality: + case BfBinaryOp_StrictEquality: + case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: case BfBinaryOp_Compare: // Still works break; @@ -18729,7 +18739,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod mResult = BfTypedValue(diffValue, intPtrType); return; } - else if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality) && + else if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_StrictEquality) && + (binaryOp != BfBinaryOp_InEquality) && (binaryOp != BfBinaryOp_StrictInEquality) && (binaryOp != BfBinaryOp_LessThan) && (binaryOp != BfBinaryOp_LessThanOrEqual) && (binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual)) { @@ -18737,8 +18748,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } - if (((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) || - (resultType != otherType)) + if ((!BfBinOpEqualityCheck(binaryOp)) || (resultType != otherType)) { resultType = mModule->GetPrimitiveType(BfTypeCode_UIntPtr); explicitCast = true; @@ -18748,13 +18758,13 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod { if (otherType->IsNull()) { - if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) + if (!BfBinOpEqualityCheck(binaryOp)) { mModule->Fail(StrFormat("Invalid operation between '%s' and null", mModule->TypeToString(resultType).c_str()), opToken); return; } - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); @@ -18796,9 +18806,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod mResult = BfTypedValue(mModule->CreateIndexedValue(underlyingType, resultTypedValue->mValue, addValue), resultType); return; } - - - + if ((resultType->IsFunction()) || (resultType->IsPointer()) || (resultType->IsObject()) || (resultType->IsInterface()) || (resultType->IsGenericParam())) { if ((binaryOp == BfBinaryOp_Add) && @@ -18809,7 +18817,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } - if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) + if (!BfGetBinaryOpPrecendence(binaryOp)) { //mModule->Fail("Invalid operation for objects", opToken); _OpFail(); @@ -18827,14 +18835,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod { if (resultType->IsFunction()) { - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); } else { - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); @@ -18845,7 +18853,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); if (!convertedValue) return; - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); @@ -18909,7 +18917,10 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod auto typeInst = leftValue.mType->ToTypeInstance(); if (typeInst != NULL) { - moduleMethodInstance = mModule->GetMethodByName(typeInst, BF_METHODNAME_DEFAULT_EQUALS); + if ((binaryOp == BfBinaryOp_StrictEquality) || (binaryOp == BfBinaryOp_StrictInEquality)) + moduleMethodInstance = mModule->GetMethodByName(typeInst, BF_METHODNAME_DEFAULT_STRICT_EQUALS); + else + moduleMethodInstance = mModule->GetMethodByName(typeInst, BF_METHODNAME_DEFAULT_EQUALS); } else { @@ -18933,7 +18944,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod resolvedArg.mTypedValue = rightValue; argValues.push_back(resolvedArg); mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, false, argValues); - if ((mResult) && (binaryOp == BfBinaryOp_InEquality)) + if ((mResult) && + ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality))) mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue); return true; } @@ -18961,7 +18973,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (leftValue.mType == rightValue.mType) { - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if (BfBinOpEqualityCheck(binaryOp)) { auto intCoercibleType = mModule->GetIntCoercibleType(leftValue.mType); if (intCoercibleType != NULL) @@ -18970,7 +18982,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod auto intRHS = mModule->GetIntCoercible(rightValue); auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(intLHS.mValue, intRHS.mValue), boolType); else mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(intLHS.mValue, intRHS.mValue), boolType); @@ -19021,7 +19033,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (resultType->IsMethodRef() && otherType->IsMethodRef()) { - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if (BfBinOpEqualityCheck(binaryOp)) { auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); @@ -19029,7 +19041,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfMethodRefType* rhsMethodRefType = (BfMethodRefType*)rightValue.mType; if (lhsMethodRefType->mMethodRef != rhsMethodRefType->mMethodRef) { - mResult = BfTypedValue(mModule->GetConstValue((binaryOp == BfBinaryOp_Equality) ? 0 : 1, boolType), boolType); + mResult = BfTypedValue(mModule->GetConstValue(((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) ? 0 : 1, boolType), boolType); return; } @@ -19056,13 +19068,15 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (leftValue.mType != rightValue.mType) { bool isBitwiseExpr = - (binaryOp == BfBinaryOp_BitwiseAnd) | - (binaryOp == BfBinaryOp_BitwiseOr) | - (binaryOp == BfBinaryOp_ExclusiveOr) | - (binaryOp == BfBinaryOp_LeftShift) | - (binaryOp == BfBinaryOp_RightShift) | - (binaryOp == BfBinaryOp_Equality) | - (binaryOp == BfBinaryOp_InEquality); + (binaryOp == BfBinaryOp_BitwiseAnd) || + (binaryOp == BfBinaryOp_BitwiseOr) || + (binaryOp == BfBinaryOp_ExclusiveOr) || + (binaryOp == BfBinaryOp_LeftShift) || + (binaryOp == BfBinaryOp_RightShift) || + (binaryOp == BfBinaryOp_Equality) || + (binaryOp == BfBinaryOp_InEquality) || + (binaryOp == BfBinaryOp_StrictEquality) || + (binaryOp == BfBinaryOp_StrictInEquality); if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift)) { @@ -19170,10 +19184,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL switch (binaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; @@ -19195,10 +19211,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL switch (binaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; @@ -19298,11 +19316,13 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL case BfBinaryOp_Modulus: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateRem(convLeftValue, convRightValue, resultType->IsSigned()), resultType); break; - case BfBinaryOp_Equality: + case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index eb13794a..7d1d58f8 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2538,7 +2538,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers return NULL; } - if (refNode != NULL) + if (refNode != NULL) refNode = BfNodeToNonTemporary(refNode); //BF_ASSERT(refNode != NULL); @@ -3973,11 +3973,11 @@ void BfModule::CreateDynamicCastMethod() mCurMethodState->mHadReturn = true; } -void BfModule::EmitEquals(BfTypedValue leftValue, BfTypedValue rightValue, BfIRBlock exitBB) +void BfModule::EmitEquals(BfTypedValue leftValue, BfTypedValue rightValue, BfIRBlock exitBB, bool strictEquals) { BfExprEvaluator exprEvaluator(this); exprEvaluator.mExpectingType = mCurMethodInstance->mReturnType; - exprEvaluator.PerformBinaryOperation((BfAstNode*)NULL, (BfAstNode*)NULL, BfBinaryOp_Equality, NULL, BfBinOpFlag_None, leftValue, rightValue); + exprEvaluator.PerformBinaryOperation((BfAstNode*)NULL, (BfAstNode*)NULL, strictEquals ? BfBinaryOp_StrictEquality : BfBinaryOp_Equality, NULL, BfBinOpFlag_None, leftValue, rightValue); BfTypedValue result = exprEvaluator.GetResult(); if ((result) && (!result.mType->IsVar())) { @@ -4036,7 +4036,7 @@ void BfModule::CreateFakeCallerMethod(const String& funcName) mBfIRBuilder->CreateRetVoid(); } -void BfModule::CreateValueTypeEqualsMethod() +void BfModule::CreateValueTypeEqualsMethod(bool strictEquals) { if (mCurMethodInstance->mIsUnspecialized) return; @@ -4109,7 +4109,7 @@ void BfModule::CreateValueTypeEqualsMethod() mBfIRBuilder->SetInsertPoint(bodyBB); BfTypedValue leftValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, GetDefaultValue(intPtrType), loadedItr), sizedArrayType->mElementType, BfTypedValueKind_Addr); BfTypedValue rightValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[1]->mValue, GetDefaultValue(intPtrType), loadedItr), sizedArrayType->mElementType, BfTypedValueKind_Addr); - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); auto incValue = mBfIRBuilder->CreateAdd(loadedItr, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 1)); mBfIRBuilder->CreateStore(incValue, itr); mBfIRBuilder->CreateBr(loopBB); @@ -4122,7 +4122,7 @@ void BfModule::CreateValueTypeEqualsMethod() { BfTypedValue leftValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, dataIdx), sizedArrayType->mElementType, BfTypedValueKind_Addr); BfTypedValue rightValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[1]->mValue, 0, dataIdx), sizedArrayType->mElementType, BfTypedValueKind_Addr); - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); } } } @@ -4144,7 +4144,7 @@ void BfModule::CreateValueTypeEqualsMethod() BfTypedValue leftValue = exprEvaluator.DoImplicitArgCapture(NULL, methodInstance, methodRefType->GetParamIdxFromDataIdx(dataIdx), failed, BfImplicitParamKind_General, leftTypedVal); BfTypedValue rightValue = exprEvaluator.DoImplicitArgCapture(NULL, methodInstance, methodRefType->GetParamIdxFromDataIdx(dataIdx), failed, BfImplicitParamKind_General, rightTypedVal); BF_ASSERT(!failed); - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); } } else if (compareTypeInst->IsEnum()) @@ -4165,7 +4165,7 @@ void BfModule::CreateValueTypeEqualsMethod() BfTypedValue leftPayload = ExtractValue(leftTypedVal, NULL, 1); BfTypedValue rightPayload = ExtractValue(rightTypedVal, NULL, 1); - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); int enumCount = 0; for (auto& fieldRef : compareTypeInst->mFieldInstances) @@ -4214,7 +4214,7 @@ void BfModule::CreateValueTypeEqualsMethod() rightTuple = Cast(NULL, rightPayload, fieldInstance->mResolvedType, BfCastFlags_Force); } - EmitEquals(leftTuple, rightTuple, exitBB); + EmitEquals(leftTuple, rightTuple, exitBB, strictEquals); mBfIRBuilder->CreateBr(matchedBlock); mBfIRBuilder->AddSwitchCase(switchVal, mBfIRBuilder->CreateConst(dscrType->mTypeDef->mTypeCode, enumIdx), caseBlock); @@ -4238,7 +4238,7 @@ void BfModule::CreateValueTypeEqualsMethod() BfTypedValue rightTypedVal = exprEvaluator.LoadLocal(mCurMethodState->mLocals[1]); BfTypedValue rightUnionTypedVal = ExtractValue(rightTypedVal, NULL, 1); - EmitEquals(leftUnionTypedVal, rightUnionTypedVal, exitBB); + EmitEquals(leftUnionTypedVal, rightUnionTypedVal, exitBB, strictEquals); } } else @@ -4266,7 +4266,7 @@ void BfModule::CreateValueTypeEqualsMethod() rightValue = LoadValue(rightValue); } - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); } auto baseTypeInst = compareTypeInst->mBaseType; @@ -4276,7 +4276,7 @@ void BfModule::CreateValueTypeEqualsMethod() BfTypedValue rightOrigValue(mCurMethodState->mLocals[1]->mValue, compareTypeInst, true); BfTypedValue leftValue = Cast(NULL, leftOrigValue, baseTypeInst); BfTypedValue rightValue = Cast(NULL, rightOrigValue, baseTypeInst); - EmitEquals(leftValue, rightValue, exitBB); + EmitEquals(leftValue, rightValue, exitBB, strictEquals); } } @@ -9927,7 +9927,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri BfConstResolver constResolver(this); if (allowNonConstArgs) constResolver.mBfEvalExprFlags = (BfEvalExprFlags)(constResolver.mBfEvalExprFlags | BfEvalExprFlags_AllowNonConst); - + bool inPropSet = false; SizedArray argValues; for (BfExpression* arg : attributesDirective->mArguments) @@ -10109,7 +10109,9 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri resolvedArg.mTypedValue = constResolver.Resolve(arg); if (!inPropSet) + { argValues.push_back(resolvedArg); + } } if (autoComplete != NULL) @@ -10128,7 +10130,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri attrTypeDef = attrTypeInst->mTypeDef; bool success = true; - + bool isFailurePass = false; for (int pass = 0; pass < 2; pass++) { @@ -17655,13 +17657,19 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) } else if (methodDef->mName == BF_METHODNAME_DEFAULT_EQUALS) { - CreateValueTypeEqualsMethod(); + CreateValueTypeEqualsMethod(false); + skipBody = true; + skipEndChecks = true; + } + else if (methodDef->mName == BF_METHODNAME_DEFAULT_STRICT_EQUALS) + { + CreateValueTypeEqualsMethod(true); skipBody = true; skipEndChecks = true; } else if ((methodDef->mName == BF_METHODNAME_EQUALS) && (typeDef == mCompiler->mValueTypeTypeDef)) { - CreateValueTypeEqualsMethod(); + CreateValueTypeEqualsMethod(false); skipBody = true; skipEndChecks = true; } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index bc6ce612..615976e3 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1745,7 +1745,7 @@ public: void EmitGCMarkMembers(); void EmitGCFindTLSMembers(); void EmitIteratorBlock(bool& skipBody); - void EmitEquals(BfTypedValue leftValue, BfTypedValue rightValue, BfIRBlock exitBB); + void EmitEquals(BfTypedValue leftValue, BfTypedValue rightValue, BfIRBlock exitBB, bool strictEquals); void CreateFakeCallerMethod(const String& funcName); void CallChainedMethods(BfMethodInstance* methodInstance, bool reverse = false); void AddHotDataReferences(BfHotDataReferenceBuilder* builder); @@ -1753,7 +1753,7 @@ public: void ProcessMethod_ProcessDeferredLocals(int startIdx = 0); void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false); void CreateDynamicCastMethod(); - void CreateValueTypeEqualsMethod(); + void CreateValueTypeEqualsMethod(bool strictEquals); BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false); BfIRFunction GetBuiltInFunc(BfBuiltInFuncType funcType); BfIRValue CreateFunctionFrom(BfMethodInstance* methodInstance, bool tryExisting, bool isInlined); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 4da684b0..f34c4107 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -3750,7 +3750,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) if (methodDef->mMethodDeclaration == NULL) { // Internal methods don't need decls - if (methodDef->mName == BF_METHODNAME_DEFAULT_EQUALS) + if ((methodDef->mName == BF_METHODNAME_DEFAULT_EQUALS) || + (methodDef->mName == BF_METHODNAME_DEFAULT_STRICT_EQUALS)) declRequired = false; } diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index c2bb796d..1fdab00f 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -1377,8 +1377,17 @@ void BfParser::NextToken(int endIdx) case '!': if (mSrc[mSrcIdx] == '=') { - mToken = BfToken_CompareNotEquals; - mTokenEnd = ++mSrcIdx; + if (mSrc[mSrcIdx + 1] == '=') + { + mToken = BfToken_CompareStrictNotEquals; + ++mSrcIdx; + mTokenEnd = ++mSrcIdx; + } + else + { + mToken = BfToken_CompareNotEquals; + mTokenEnd = ++mSrcIdx; + } } else mToken = BfToken_Bang; @@ -1387,8 +1396,17 @@ void BfParser::NextToken(int endIdx) case '=': if (mSrc[mSrcIdx] == '=') { - mToken = BfToken_CompareEquals; - mTokenEnd = ++mSrcIdx; + if (mSrc[mSrcIdx + 1] == '=') + { + mToken = BfToken_CompareStrictEquals; + ++mSrcIdx; + mTokenEnd = ++mSrcIdx; + } + else + { + mToken = BfToken_CompareEquals; + mTokenEnd = ++mSrcIdx; + } } else if (mSrc[mSrcIdx] == '>') { diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index a3130eac..45ea94d3 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -657,6 +657,7 @@ enum BfCallingConvention : uint8 #define BF_METHODNAME_INVOKE "Invoke" #define BF_METHODNAME_TO_STRING "ToString" #define BF_METHODNAME_DEFAULT_EQUALS "__Equals" +#define BF_METHODNAME_DEFAULT_STRICT_EQUALS "__StrictEquals" enum BfOptimize : int8 { diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 7a13dc43..f2587f35 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -5646,7 +5646,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress if ((resultTypedValue->mIsLiteral) && (resultType->IsPointer())) { // If we're comparing against a string literal like 'str == "Hey!"', handle that - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) + if (BfBinOpEqualityCheck(binaryOp)) { DbgType* useType = otherType; useType = useType->RemoveModifiers(); @@ -5689,7 +5689,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = boolType; - mResult.mBool = isEq == (binaryOp == BfBinaryOp_Equality); + mResult.mBool = isEq == ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)); return; } } @@ -5708,9 +5708,9 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress return; }*/ - if ((otherType->IsNull()) && ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality))) + if ((otherType->IsNull()) && BfBinOpEqualityCheck(binaryOp)) { - bool isEquality = (binaryOp == BfBinaryOp_Equality); + bool isEquality = (binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality); if (resultType->IsValueType()) { @@ -5801,7 +5801,8 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress mResult.mType = intPtrType; return; } - else if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality) && + else if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_StrictEquality) & + (binaryOp != BfBinaryOp_InEquality) && (binaryOp != BfBinaryOp_StrictInEquality) && (binaryOp != BfBinaryOp_LessThan) && (binaryOp != BfBinaryOp_LessThanOrEqual) && (binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual)) { @@ -5817,7 +5818,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress { if (otherType->IsNull()) { - if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) + if (!BfBinOpEqualityCheck(binaryOp)) { Fail(StrFormat("Invalid operation between '%s' and null", resultType->ToString().c_str()), opToken); return; @@ -5870,7 +5871,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress if ((resultType->IsPointer()) || (resultType->IsBfObject()) || (resultType->IsInterface()) /*|| (resultType->IsGenericParam())*/) { - if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) + if (!BfBinOpEqualityCheck(binaryOp)) { if (resultType->IsPointer()) Fail("Invalid operation for pointers", opToken); @@ -5882,7 +5883,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress if (otherType->IsNull()) { mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult.mBool = resultTypedValue->mPtr == NULL; else mResult.mBool = resultTypedValue->mPtr != NULL; @@ -5898,7 +5899,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress return; mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); - if (binaryOp == BfBinaryOp_Equality) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) mResult.mBool = resultTypedValue->mPtr == convertedValue.mPtr; else mResult.mBool = resultTypedValue->mPtr != convertedValue.mPtr; @@ -6035,10 +6036,12 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue switch (binaryOp) { case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mBool = true; break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mBool = false; break; @@ -6063,10 +6066,12 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); switch (binaryOp) { - case BfBinaryOp_Equality: + case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult.mBool = convLeftValue.mBool == convRightValue.mBool; break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult.mBool = convLeftValue.mBool != convRightValue.mBool; break; case BfBinaryOp_ConditionalAnd: @@ -6182,6 +6187,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue } break; case BfBinaryOp_Equality: + case BfBinaryOp_StrictEquality: mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); if (resultType->mTypeCode == DbgType_Single) mResult.mBool = convLeftValue.mSingle == convRightValue.mSingle; @@ -6191,6 +6197,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue mResult.mBool = convLeftValue.GetInt64() == convRightValue.GetInt64(); break; case BfBinaryOp_InEquality: + case BfBinaryOp_StrictInEquality: mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); if (resultType->mTypeCode == DbgType_Single) mResult.mBool = convLeftValue.mSingle != convRightValue.mSingle;