1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Added concept of strict equality

This commit is contained in:
Brian Fiete 2020-06-17 05:13:53 -07:00
parent 308605a7dd
commit abeda6909b
13 changed files with 249 additions and 79 deletions

View file

@ -420,14 +420,6 @@ namespace System.Collections
return -1; 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) public int IndexOf(T item, int index)
{ {
for (int i = index; i < mSize; i++) for (int i = index; i < mSize; i++)
@ -444,6 +436,46 @@ namespace System.Collections
return -1; 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) public void Insert(int index, T item)
{ {
var item; // This creates a copy - required if item is a ref to an element var item; // This creates a copy - required if item is a ref to an element
@ -577,6 +609,31 @@ namespace System.Collections
return false; return false;
} }
public bool RemoveStrict(T item)
{
int index = IndexOfStrict(item);
if (index >= 0)
{
RemoveAt(index);
return true;
}
return false;
}
public Result<T> 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 /// 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 /// list does not contain the given value, the method returns a negative
/// integer. The bitwise complement operator (~) can be applied to a /// integer. The bitwise complement operator (~) can be applied to a

View file

@ -147,6 +147,22 @@ namespace System
mLength = 0; 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 public void RemoveFromStart(int length) mut
{ {
Debug.Assert((uint)length <= (uint)mLength); Debug.Assert((uint)length <= (uint)mLength);

View file

@ -328,8 +328,8 @@ namespace IDE.Compiler
if (oldIdx <= expectedOldIdx) if (oldIdx <= expectedOldIdx)
{ {
#if DEBUG #if DEBUG
Utils.WriteTextFile(@"c:\temp\old.txt", oldText); Utils.WriteTextFile(@"c:\temp\old.txt", oldText).IgnoreError();
Utils.WriteTextFile(@"c:\temp\new.txt", newText); Utils.WriteTextFile(@"c:\temp\new.txt", newText).IgnoreError();
Debug.FatalError("Reformat failed"); Debug.FatalError("Reformat failed");
#endif #endif
break; // Error - abort break; // Error - abort

View file

@ -1303,6 +1303,8 @@ const char* Beefy::BfTokenToString(BfToken token)
return "mixin"; return "mixin";
case BfToken_Mut: case BfToken_Mut:
return "mut"; return "mut";
case BfToken_NameOf:
return "nameof";
case BfToken_Namespace: case BfToken_Namespace:
return "namespace"; return "namespace";
case BfToken_New: case BfToken_New:
@ -1385,8 +1387,12 @@ const char* Beefy::BfTokenToString(BfToken token)
return "="; return "=";
case BfToken_CompareEquals: case BfToken_CompareEquals:
return "=="; return "==";
case BfToken_CompareStrictEquals:
return "===";
case BfToken_CompareNotEquals: case BfToken_CompareNotEquals:
return "!="; return "!=";
case BfToken_CompareStrictNotEquals:
return "!==";
case BfToken_LessEquals: case BfToken_LessEquals:
return "<="; return "<=";
case BfToken_GreaterEquals: case BfToken_GreaterEquals:
@ -1559,7 +1565,9 @@ int Beefy::BfGetBinaryOpPrecendence(BfBinaryOp binOp)
case BfBinaryOp_LessThanOrEqual: case BfBinaryOp_LessThanOrEqual:
return 5; return 5;
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
return 4; return 4;
case BfBinaryOp_ConditionalAnd: case BfBinaryOp_ConditionalAnd:
return 3; return 3;
@ -1590,7 +1598,9 @@ const char* Beefy::BfGetOpName(BfBinaryOp binOp)
case BfBinaryOp_LeftShift: return "<<"; case BfBinaryOp_LeftShift: return "<<";
case BfBinaryOp_RightShift: return ">>"; case BfBinaryOp_RightShift: return ">>";
case BfBinaryOp_Equality: return "=="; case BfBinaryOp_Equality: return "==";
case BfBinaryOp_StrictEquality: return "===";
case BfBinaryOp_InEquality: return "!="; case BfBinaryOp_InEquality: return "!=";
case BfBinaryOp_StrictInEquality: return "!==";
case BfBinaryOp_GreaterThan: return ">"; case BfBinaryOp_GreaterThan: return ">";
case BfBinaryOp_LessThan: return "<"; case BfBinaryOp_LessThan: return "<";
case BfBinaryOp_GreaterThanOrEqual: return ">="; case BfBinaryOp_GreaterThanOrEqual: return ">=";
@ -1655,8 +1665,12 @@ BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token)
return BfBinaryOp_RightShift; return BfBinaryOp_RightShift;
case BfToken_CompareEquals: case BfToken_CompareEquals:
return BfBinaryOp_Equality; return BfBinaryOp_Equality;
case BfToken_CompareStrictEquals:
return BfBinaryOp_StrictEquality;
case BfToken_CompareNotEquals: case BfToken_CompareNotEquals:
return BfBinaryOp_InEquality; return BfBinaryOp_InEquality;
case BfToken_CompareStrictNotEquals:
return BfBinaryOp_StrictInEquality;
case BfToken_RChevron: case BfToken_RChevron:
return BfBinaryOp_GreaterThan; return BfBinaryOp_GreaterThan;
case BfToken_LChevron: case BfToken_LChevron:
@ -1770,8 +1784,12 @@ BfBinaryOp Beefy::BfGetOppositeBinaryOp(BfBinaryOp origOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
return BfBinaryOp_InEquality; return BfBinaryOp_InEquality;
case BfBinaryOp_StrictEquality:
return BfBinaryOp_StrictInEquality;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
return BfBinaryOp_Equality; return BfBinaryOp_Equality;
case BfBinaryOp_StrictInEquality:
return BfBinaryOp_StrictEquality;
case BfBinaryOp_LessThan: case BfBinaryOp_LessThan:
return BfBinaryOp_GreaterThanOrEqual; return BfBinaryOp_GreaterThanOrEqual;
case BfBinaryOp_LessThanOrEqual: case BfBinaryOp_LessThanOrEqual:
@ -1808,6 +1826,11 @@ BfBinaryOp Beefy::BfGetFlippedBinaryOp(BfBinaryOp origOp)
return BfBinaryOp_None; return BfBinaryOp_None;
} }
bool Beefy::BfBinOpEqualityCheck(BfBinaryOp binOp)
{
return (binOp >= BfBinaryOp_Equality) && (binOp <= BfBinaryOp_StrictInEquality);
}
bool Beefy::BfIsCommentBlock(BfCommentKind commentKind) bool Beefy::BfIsCommentBlock(BfCommentKind commentKind)
{ {
return return

View file

@ -146,6 +146,7 @@ enum BfToken : uint8
BfToken_Let, BfToken_Let,
BfToken_Mixin, BfToken_Mixin,
BfToken_Mut, BfToken_Mut,
BfToken_NameOf,
BfToken_Namespace, BfToken_Namespace,
BfToken_New, BfToken_New,
BfToken_Null, BfToken_Null,
@ -187,7 +188,9 @@ enum BfToken : uint8
BfToken_Yield, BfToken_Yield,
BfToken_AssignEquals, BfToken_AssignEquals,
BfToken_CompareEquals, BfToken_CompareEquals,
BfToken_CompareStrictEquals,
BfToken_CompareNotEquals, BfToken_CompareNotEquals,
BfToken_CompareStrictNotEquals,
BfToken_LessEquals, BfToken_LessEquals,
BfToken_GreaterEquals, BfToken_GreaterEquals,
BfToken_Spaceship, BfToken_Spaceship,
@ -1706,7 +1709,9 @@ enum BfBinaryOp
BfBinaryOp_LeftShift, BfBinaryOp_LeftShift,
BfBinaryOp_RightShift, BfBinaryOp_RightShift,
BfBinaryOp_Equality, BfBinaryOp_Equality,
BfBinaryOp_StrictEquality,
BfBinaryOp_InEquality, BfBinaryOp_InEquality,
BfBinaryOp_StrictInEquality,
BfBinaryOp_GreaterThan, BfBinaryOp_GreaterThan,
BfBinaryOp_LessThan, BfBinaryOp_LessThan,
BfBinaryOp_GreaterThanOrEqual, BfBinaryOp_GreaterThanOrEqual,
@ -3199,6 +3204,7 @@ bool BfTokenIsKeyword(BfToken token);
BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp); BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp);
BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp); BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp);
BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp); BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp);
bool BfBinOpEqualityCheck(BfBinaryOp binOp);
int BfGetBinaryOpPrecendence(BfBinaryOp binOp); int BfGetBinaryOpPrecendence(BfBinaryOp binOp);
const char* BfGetOpName(BfBinaryOp binOp); const char* BfGetOpName(BfBinaryOp binOp);
const char* BfGetOpName(BfUnaryOp unaryOp); const char* BfGetOpName(BfUnaryOp unaryOp);

View file

@ -2061,6 +2061,19 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
AddParam(methodDef, mSystem->mDirectSelfTypeRef, "rhs"); 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; HashContext inlineHashCtx;
if (mCurSource != NULL) if (mCurSource != NULL)

View file

@ -18009,10 +18009,12 @@ bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken,
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
if (rightConst->mInt64 < minValue) if (rightConst->mInt64 < minValue)
constResult = 0; constResult = 0;
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
if (rightConst->mInt64 < minValue) if (rightConst->mInt64 < minValue)
constResult = 1; constResult = 1;
break; break;
@ -18033,12 +18035,14 @@ bool BfExprEvaluator::CheckConstCompare(BfBinaryOp binaryOp, BfAstNode* opToken,
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
if (rightConst->mInt64 < minValue) if (rightConst->mInt64 < minValue)
constResult = 0; constResult = 0;
else if (rightConst->mInt64 > maxValue) else if (rightConst->mInt64 > maxValue)
constResult = 0; constResult = 0;
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
if (rightConst->mInt64 < minValue) if (rightConst->mInt64 < minValue)
constResult = 1; constResult = 1;
else if (rightConst->mInt64 > maxValue) 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 // 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))) if ((resultType != otherType) && (resultTypedValue->mValue.IsConst()) && (mModule->CanCast(*resultTypedValue, otherType)))
{ {
@ -18351,9 +18355,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
return; 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())) if ((resultType->IsValueType()) && (!resultType->IsFunction()))
{ {
@ -18408,7 +18412,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
} }
// Check for constant equality checks (mostly for strings) // 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 leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue);
auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue); auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue);
@ -18423,7 +18427,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (rightStringPoolIdx != -1) if (rightStringPoolIdx != -1)
{ {
bool isEqual = leftStringPoolIdx == rightStringPoolIdx; bool isEqual = leftStringPoolIdx == rightStringPoolIdx;
if (binaryOp == BfBinaryOp_InEquality) if ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality))
isEqual = !isEqual; isEqual = !isEqual;
mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType); mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType);
return; return;
@ -18434,7 +18438,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (eqResult != -1) if (eqResult != -1)
{ {
bool isEqual = eqResult == 1; bool isEqual = eqResult == 1;
if (binaryOp == BfBinaryOp_InEquality) if ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality))
isEqual = !isEqual; isEqual = !isEqual;
mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType); mResult = BfTypedValue(mModule->GetConstValue(isEqual ? 1 : 0, boolType), boolType);
return; return;
@ -18447,7 +18451,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{ {
// As an optimization, we don't call user operator overloads for null checks // As an optimization, we don't call user operator overloads for null checks
bool skipOpOverload = false; 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 leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue);
auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue); auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue);
@ -18593,9 +18599,11 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
switch (useBinaryOp) switch (useBinaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mResult.mValue, zeroVal), boolType); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mResult.mValue, zeroVal), boolType);
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mResult.mValue, zeroVal), boolType); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mResult.mValue, zeroVal), boolType);
break; break;
case BfBinaryOp_GreaterThan: case BfBinaryOp_GreaterThan:
@ -18667,7 +18675,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
switch (findBinaryOp) switch (findBinaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
case BfBinaryOp_Compare: case BfBinaryOp_Compare:
// Still works // Still works
break; break;
@ -18729,7 +18739,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
mResult = BfTypedValue(diffValue, intPtrType); mResult = BfTypedValue(diffValue, intPtrType);
return; 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_LessThan) && (binaryOp != BfBinaryOp_LessThanOrEqual) &&
(binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual)) (binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual))
{ {
@ -18737,8 +18748,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
return; return;
} }
if (((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) || if ((!BfBinOpEqualityCheck(binaryOp)) || (resultType != otherType))
(resultType != otherType))
{ {
resultType = mModule->GetPrimitiveType(BfTypeCode_UIntPtr); resultType = mModule->GetPrimitiveType(BfTypeCode_UIntPtr);
explicitCast = true; explicitCast = true;
@ -18748,13 +18758,13 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{ {
if (otherType->IsNull()) 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); mModule->Fail(StrFormat("Invalid operation between '%s' and null", mModule->TypeToString(resultType).c_str()), opToken);
return; return;
} }
if (binaryOp == BfBinaryOp_Equality) if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
else else
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
@ -18797,8 +18807,6 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
return; return;
} }
if ((resultType->IsFunction()) || (resultType->IsPointer()) || (resultType->IsObject()) || (resultType->IsInterface()) || (resultType->IsGenericParam())) if ((resultType->IsFunction()) || (resultType->IsPointer()) || (resultType->IsObject()) || (resultType->IsInterface()) || (resultType->IsGenericParam()))
{ {
if ((binaryOp == BfBinaryOp_Add) && if ((binaryOp == BfBinaryOp_Add) &&
@ -18809,7 +18817,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
return; return;
} }
if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) if (!BfGetBinaryOpPrecendence(binaryOp))
{ {
//mModule->Fail("Invalid operation for objects", opToken); //mModule->Fail("Invalid operation for objects", opToken);
_OpFail(); _OpFail();
@ -18827,14 +18835,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{ {
if (resultType->IsFunction()) 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)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
else else
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
} }
else else
{ {
if (binaryOp == BfBinaryOp_Equality) if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
else else
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); 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); auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
if (!convertedValue) if (!convertedValue)
return; return;
if (binaryOp == BfBinaryOp_Equality) if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
else else
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
@ -18909,6 +18917,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
auto typeInst = leftValue.mType->ToTypeInstance(); auto typeInst = leftValue.mType->ToTypeInstance();
if (typeInst != NULL) if (typeInst != NULL)
{ {
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); moduleMethodInstance = mModule->GetMethodByName(typeInst, BF_METHODNAME_DEFAULT_EQUALS);
} }
else else
@ -18933,7 +18944,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
resolvedArg.mTypedValue = rightValue; resolvedArg.mTypedValue = rightValue;
argValues.push_back(resolvedArg); argValues.push_back(resolvedArg);
mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, false, argValues); 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); mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue);
return true; return true;
} }
@ -18961,7 +18973,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (leftValue.mType == rightValue.mType) if (leftValue.mType == rightValue.mType)
{ {
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) if (BfBinOpEqualityCheck(binaryOp))
{ {
auto intCoercibleType = mModule->GetIntCoercibleType(leftValue.mType); auto intCoercibleType = mModule->GetIntCoercibleType(leftValue.mType);
if (intCoercibleType != NULL) if (intCoercibleType != NULL)
@ -18970,7 +18982,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
auto intRHS = mModule->GetIntCoercible(rightValue); auto intRHS = mModule->GetIntCoercible(rightValue);
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); 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); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(intLHS.mValue, intRHS.mValue), boolType);
else else
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(intLHS.mValue, intRHS.mValue), boolType); 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 (resultType->IsMethodRef() && otherType->IsMethodRef())
{ {
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_InEquality)) if (BfBinOpEqualityCheck(binaryOp))
{ {
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean);
@ -19029,7 +19041,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
BfMethodRefType* rhsMethodRefType = (BfMethodRefType*)rightValue.mType; BfMethodRefType* rhsMethodRefType = (BfMethodRefType*)rightValue.mType;
if (lhsMethodRefType->mMethodRef != rhsMethodRefType->mMethodRef) 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; return;
} }
@ -19056,13 +19068,15 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (leftValue.mType != rightValue.mType) if (leftValue.mType != rightValue.mType)
{ {
bool isBitwiseExpr = bool isBitwiseExpr =
(binaryOp == BfBinaryOp_BitwiseAnd) | (binaryOp == BfBinaryOp_BitwiseAnd) ||
(binaryOp == BfBinaryOp_BitwiseOr) | (binaryOp == BfBinaryOp_BitwiseOr) ||
(binaryOp == BfBinaryOp_ExclusiveOr) | (binaryOp == BfBinaryOp_ExclusiveOr) ||
(binaryOp == BfBinaryOp_LeftShift) | (binaryOp == BfBinaryOp_LeftShift) ||
(binaryOp == BfBinaryOp_RightShift) | (binaryOp == BfBinaryOp_RightShift) ||
(binaryOp == BfBinaryOp_Equality) | (binaryOp == BfBinaryOp_Equality) ||
(binaryOp == BfBinaryOp_InEquality); (binaryOp == BfBinaryOp_InEquality) ||
(binaryOp == BfBinaryOp_StrictEquality) ||
(binaryOp == BfBinaryOp_StrictInEquality);
if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift)) if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
{ {
@ -19170,10 +19184,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;
@ -19195,10 +19211,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;
@ -19299,10 +19317,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateRem(convLeftValue, convRightValue, resultType->IsSigned()), resultType); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateRem(convLeftValue, convRightValue, resultType->IsSigned()), resultType);
break; break;
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(convLeftValue, convRightValue),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue), mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(convLeftValue, convRightValue),
mModule->GetPrimitiveType(BfTypeCode_Boolean)); mModule->GetPrimitiveType(BfTypeCode_Boolean));
break; break;

View file

@ -3973,11 +3973,11 @@ void BfModule::CreateDynamicCastMethod()
mCurMethodState->mHadReturn = true; 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); BfExprEvaluator exprEvaluator(this);
exprEvaluator.mExpectingType = mCurMethodInstance->mReturnType; 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(); BfTypedValue result = exprEvaluator.GetResult();
if ((result) && (!result.mType->IsVar())) if ((result) && (!result.mType->IsVar()))
{ {
@ -4036,7 +4036,7 @@ void BfModule::CreateFakeCallerMethod(const String& funcName)
mBfIRBuilder->CreateRetVoid(); mBfIRBuilder->CreateRetVoid();
} }
void BfModule::CreateValueTypeEqualsMethod() void BfModule::CreateValueTypeEqualsMethod(bool strictEquals)
{ {
if (mCurMethodInstance->mIsUnspecialized) if (mCurMethodInstance->mIsUnspecialized)
return; return;
@ -4109,7 +4109,7 @@ void BfModule::CreateValueTypeEqualsMethod()
mBfIRBuilder->SetInsertPoint(bodyBB); mBfIRBuilder->SetInsertPoint(bodyBB);
BfTypedValue leftValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, GetDefaultValue(intPtrType), loadedItr), sizedArrayType->mElementType, BfTypedValueKind_Addr); 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); 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)); auto incValue = mBfIRBuilder->CreateAdd(loadedItr, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 1));
mBfIRBuilder->CreateStore(incValue, itr); mBfIRBuilder->CreateStore(incValue, itr);
mBfIRBuilder->CreateBr(loopBB); 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 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); 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 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); BfTypedValue rightValue = exprEvaluator.DoImplicitArgCapture(NULL, methodInstance, methodRefType->GetParamIdxFromDataIdx(dataIdx), failed, BfImplicitParamKind_General, rightTypedVal);
BF_ASSERT(!failed); BF_ASSERT(!failed);
EmitEquals(leftValue, rightValue, exitBB); EmitEquals(leftValue, rightValue, exitBB, strictEquals);
} }
} }
else if (compareTypeInst->IsEnum()) else if (compareTypeInst->IsEnum())
@ -4165,7 +4165,7 @@ void BfModule::CreateValueTypeEqualsMethod()
BfTypedValue leftPayload = ExtractValue(leftTypedVal, NULL, 1); BfTypedValue leftPayload = ExtractValue(leftTypedVal, NULL, 1);
BfTypedValue rightPayload = ExtractValue(rightTypedVal, NULL, 1); BfTypedValue rightPayload = ExtractValue(rightTypedVal, NULL, 1);
EmitEquals(leftValue, rightValue, exitBB); EmitEquals(leftValue, rightValue, exitBB, strictEquals);
int enumCount = 0; int enumCount = 0;
for (auto& fieldRef : compareTypeInst->mFieldInstances) for (auto& fieldRef : compareTypeInst->mFieldInstances)
@ -4214,7 +4214,7 @@ void BfModule::CreateValueTypeEqualsMethod()
rightTuple = Cast(NULL, rightPayload, fieldInstance->mResolvedType, BfCastFlags_Force); rightTuple = Cast(NULL, rightPayload, fieldInstance->mResolvedType, BfCastFlags_Force);
} }
EmitEquals(leftTuple, rightTuple, exitBB); EmitEquals(leftTuple, rightTuple, exitBB, strictEquals);
mBfIRBuilder->CreateBr(matchedBlock); mBfIRBuilder->CreateBr(matchedBlock);
mBfIRBuilder->AddSwitchCase(switchVal, mBfIRBuilder->CreateConst(dscrType->mTypeDef->mTypeCode, enumIdx), caseBlock); 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 rightTypedVal = exprEvaluator.LoadLocal(mCurMethodState->mLocals[1]);
BfTypedValue rightUnionTypedVal = ExtractValue(rightTypedVal, NULL, 1); BfTypedValue rightUnionTypedVal = ExtractValue(rightTypedVal, NULL, 1);
EmitEquals(leftUnionTypedVal, rightUnionTypedVal, exitBB); EmitEquals(leftUnionTypedVal, rightUnionTypedVal, exitBB, strictEquals);
} }
} }
else else
@ -4266,7 +4266,7 @@ void BfModule::CreateValueTypeEqualsMethod()
rightValue = LoadValue(rightValue); rightValue = LoadValue(rightValue);
} }
EmitEquals(leftValue, rightValue, exitBB); EmitEquals(leftValue, rightValue, exitBB, strictEquals);
} }
auto baseTypeInst = compareTypeInst->mBaseType; auto baseTypeInst = compareTypeInst->mBaseType;
@ -4276,7 +4276,7 @@ void BfModule::CreateValueTypeEqualsMethod()
BfTypedValue rightOrigValue(mCurMethodState->mLocals[1]->mValue, compareTypeInst, true); BfTypedValue rightOrigValue(mCurMethodState->mLocals[1]->mValue, compareTypeInst, true);
BfTypedValue leftValue = Cast(NULL, leftOrigValue, baseTypeInst); BfTypedValue leftValue = Cast(NULL, leftOrigValue, baseTypeInst);
BfTypedValue rightValue = Cast(NULL, rightOrigValue, baseTypeInst); BfTypedValue rightValue = Cast(NULL, rightOrigValue, baseTypeInst);
EmitEquals(leftValue, rightValue, exitBB); EmitEquals(leftValue, rightValue, exitBB, strictEquals);
} }
} }
@ -10109,8 +10109,10 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
resolvedArg.mTypedValue = constResolver.Resolve(arg); resolvedArg.mTypedValue = constResolver.Resolve(arg);
if (!inPropSet) if (!inPropSet)
{
argValues.push_back(resolvedArg); argValues.push_back(resolvedArg);
} }
}
if (autoComplete != NULL) if (autoComplete != NULL)
autoComplete->mShowAttributeProperties = NULL; autoComplete->mShowAttributeProperties = NULL;
@ -17655,13 +17657,19 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
} }
else if (methodDef->mName == BF_METHODNAME_DEFAULT_EQUALS) 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; skipBody = true;
skipEndChecks = true; skipEndChecks = true;
} }
else if ((methodDef->mName == BF_METHODNAME_EQUALS) && (typeDef == mCompiler->mValueTypeTypeDef)) else if ((methodDef->mName == BF_METHODNAME_EQUALS) && (typeDef == mCompiler->mValueTypeTypeDef))
{ {
CreateValueTypeEqualsMethod(); CreateValueTypeEqualsMethod(false);
skipBody = true; skipBody = true;
skipEndChecks = true; skipEndChecks = true;
} }

View file

@ -1745,7 +1745,7 @@ public:
void EmitGCMarkMembers(); void EmitGCMarkMembers();
void EmitGCFindTLSMembers(); void EmitGCFindTLSMembers();
void EmitIteratorBlock(bool& skipBody); 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 CreateFakeCallerMethod(const String& funcName);
void CallChainedMethods(BfMethodInstance* methodInstance, bool reverse = false); void CallChainedMethods(BfMethodInstance* methodInstance, bool reverse = false);
void AddHotDataReferences(BfHotDataReferenceBuilder* builder); void AddHotDataReferences(BfHotDataReferenceBuilder* builder);
@ -1753,7 +1753,7 @@ public:
void ProcessMethod_ProcessDeferredLocals(int startIdx = 0); void ProcessMethod_ProcessDeferredLocals(int startIdx = 0);
void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false); void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false);
void CreateDynamicCastMethod(); void CreateDynamicCastMethod();
void CreateValueTypeEqualsMethod(); void CreateValueTypeEqualsMethod(bool strictEquals);
BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false); BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false);
BfIRFunction GetBuiltInFunc(BfBuiltInFuncType funcType); BfIRFunction GetBuiltInFunc(BfBuiltInFuncType funcType);
BfIRValue CreateFunctionFrom(BfMethodInstance* methodInstance, bool tryExisting, bool isInlined); BfIRValue CreateFunctionFrom(BfMethodInstance* methodInstance, bool tryExisting, bool isInlined);

View file

@ -3750,7 +3750,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
if (methodDef->mMethodDeclaration == NULL) if (methodDef->mMethodDeclaration == NULL)
{ {
// Internal methods don't need decls // 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; declRequired = false;
} }

View file

@ -1376,20 +1376,38 @@ void BfParser::NextToken(int endIdx)
{ {
case '!': case '!':
if (mSrc[mSrcIdx] == '=') if (mSrc[mSrcIdx] == '=')
{
if (mSrc[mSrcIdx + 1] == '=')
{
mToken = BfToken_CompareStrictNotEquals;
++mSrcIdx;
mTokenEnd = ++mSrcIdx;
}
else
{ {
mToken = BfToken_CompareNotEquals; mToken = BfToken_CompareNotEquals;
mTokenEnd = ++mSrcIdx; mTokenEnd = ++mSrcIdx;
} }
}
else else
mToken = BfToken_Bang; mToken = BfToken_Bang;
mSyntaxToken = BfSyntaxToken_Token; mSyntaxToken = BfSyntaxToken_Token;
return; return;
case '=': case '=':
if (mSrc[mSrcIdx] == '=') if (mSrc[mSrcIdx] == '=')
{
if (mSrc[mSrcIdx + 1] == '=')
{
mToken = BfToken_CompareStrictEquals;
++mSrcIdx;
mTokenEnd = ++mSrcIdx;
}
else
{ {
mToken = BfToken_CompareEquals; mToken = BfToken_CompareEquals;
mTokenEnd = ++mSrcIdx; mTokenEnd = ++mSrcIdx;
} }
}
else if (mSrc[mSrcIdx] == '>') else if (mSrc[mSrcIdx] == '>')
{ {
mToken = BfToken_FatArrow; mToken = BfToken_FatArrow;

View file

@ -657,6 +657,7 @@ enum BfCallingConvention : uint8
#define BF_METHODNAME_INVOKE "Invoke" #define BF_METHODNAME_INVOKE "Invoke"
#define BF_METHODNAME_TO_STRING "ToString" #define BF_METHODNAME_TO_STRING "ToString"
#define BF_METHODNAME_DEFAULT_EQUALS "__Equals" #define BF_METHODNAME_DEFAULT_EQUALS "__Equals"
#define BF_METHODNAME_DEFAULT_STRICT_EQUALS "__StrictEquals"
enum BfOptimize : int8 enum BfOptimize : int8
{ {

View file

@ -5646,7 +5646,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
if ((resultTypedValue->mIsLiteral) && (resultType->IsPointer())) if ((resultTypedValue->mIsLiteral) && (resultType->IsPointer()))
{ {
// If we're comparing against a string literal like 'str == "Hey!"', handle that // 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; DbgType* useType = otherType;
useType = useType->RemoveModifiers(); useType = useType->RemoveModifiers();
@ -5689,7 +5689,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); auto boolType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mType = boolType; mResult.mType = boolType;
mResult.mBool = isEq == (binaryOp == BfBinaryOp_Equality); mResult.mBool = isEq == ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality));
return; return;
} }
} }
@ -5708,9 +5708,9 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
return; 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()) if (resultType->IsValueType())
{ {
@ -5801,7 +5801,8 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
mResult.mType = intPtrType; mResult.mType = intPtrType;
return; 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_LessThan) && (binaryOp != BfBinaryOp_LessThanOrEqual) &&
(binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual)) (binaryOp != BfBinaryOp_GreaterThan) && (binaryOp != BfBinaryOp_GreaterThanOrEqual))
{ {
@ -5817,7 +5818,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
{ {
if (otherType->IsNull()) 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); Fail(StrFormat("Invalid operation between '%s' and null", resultType->ToString().c_str()), opToken);
return; return;
@ -5870,7 +5871,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
if ((resultType->IsPointer()) || (resultType->IsBfObject()) || (resultType->IsInterface()) /*|| (resultType->IsGenericParam())*/) if ((resultType->IsPointer()) || (resultType->IsBfObject()) || (resultType->IsInterface()) /*|| (resultType->IsGenericParam())*/)
{ {
if ((binaryOp != BfBinaryOp_Equality) && (binaryOp != BfBinaryOp_InEquality)) if (!BfBinOpEqualityCheck(binaryOp))
{ {
if (resultType->IsPointer()) if (resultType->IsPointer())
Fail("Invalid operation for pointers", opToken); Fail("Invalid operation for pointers", opToken);
@ -5882,7 +5883,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
if (otherType->IsNull()) if (otherType->IsNull())
{ {
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (binaryOp == BfBinaryOp_Equality) if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult.mBool = resultTypedValue->mPtr == NULL; mResult.mBool = resultTypedValue->mPtr == NULL;
else else
mResult.mBool = resultTypedValue->mPtr != NULL; mResult.mBool = resultTypedValue->mPtr != NULL;
@ -5898,7 +5899,7 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress
return; return;
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (binaryOp == BfBinaryOp_Equality) if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult.mBool = resultTypedValue->mPtr == convertedValue.mPtr; mResult.mBool = resultTypedValue->mPtr == convertedValue.mPtr;
else else
mResult.mBool = resultTypedValue->mPtr != convertedValue.mPtr; mResult.mBool = resultTypedValue->mPtr != convertedValue.mPtr;
@ -6035,10 +6036,12 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mBool = true; mResult.mBool = true;
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
mResult.mBool = false; mResult.mBool = false;
break; break;
@ -6064,9 +6067,11 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue
switch (binaryOp) switch (binaryOp)
{ {
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult.mBool = convLeftValue.mBool == convRightValue.mBool; mResult.mBool = convLeftValue.mBool == convRightValue.mBool;
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult.mBool = convLeftValue.mBool != convRightValue.mBool; mResult.mBool = convLeftValue.mBool != convRightValue.mBool;
break; break;
case BfBinaryOp_ConditionalAnd: case BfBinaryOp_ConditionalAnd:
@ -6182,6 +6187,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue
} }
break; break;
case BfBinaryOp_Equality: case BfBinaryOp_Equality:
case BfBinaryOp_StrictEquality:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single) if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle == convRightValue.mSingle; mResult.mBool = convLeftValue.mSingle == convRightValue.mSingle;
@ -6191,6 +6197,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue
mResult.mBool = convLeftValue.GetInt64() == convRightValue.GetInt64(); mResult.mBool = convLeftValue.GetInt64() == convRightValue.GetInt64();
break; break;
case BfBinaryOp_InEquality: case BfBinaryOp_InEquality:
case BfBinaryOp_StrictInEquality:
mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage()); mResult.mType = mDbgModule->GetPrimitiveType(DbgType_Bool, GetLanguage());
if (resultType->mTypeCode == DbgType_Single) if (resultType->mTypeCode == DbgType_Single)
mResult.mBool = convLeftValue.mSingle != convRightValue.mSingle; mResult.mBool = convLeftValue.mSingle != convRightValue.mSingle;