mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
New nullable support
This commit is contained in:
parent
59233cc996
commit
88adb3a1cd
16 changed files with 963 additions and 143 deletions
|
@ -414,8 +414,7 @@ namespace System.Collections.Generic
|
||||||
int_cosize* newBuckets = new int_cosize[newSize]*;
|
int_cosize* newBuckets = new int_cosize[newSize]*;
|
||||||
for (int_cosize i = 0; i < newSize; i++) newBuckets[i] = -1;
|
for (int_cosize i = 0; i < newSize; i++) newBuckets[i] = -1;
|
||||||
Entry* newEntries = new Entry[newSize]*;
|
Entry* newEntries = new Entry[newSize]*;
|
||||||
//mEntries.CopyTo(newEntries, 0, 0, mCount);
|
Internal.MemCpy(newEntries, mEntries, mCount * strideof(Entry), alignof(Entry));
|
||||||
Internal.MemCpy(newEntries, mEntries, mCount * sizeof(Entry), alignof(Entry));
|
|
||||||
|
|
||||||
if (forceNewHashCodes)
|
if (forceNewHashCodes)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,83 +1,62 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace System
|
namespace System
|
||||||
{
|
{
|
||||||
public struct Nullable<T> where T : struct
|
struct Nullable<T> where T : struct
|
||||||
{
|
{
|
||||||
#region Sync with runtime code
|
internal T mValue;
|
||||||
internal T mValue;
|
|
||||||
internal bool mHasValue;
|
internal bool mHasValue;
|
||||||
#endregion
|
|
||||||
|
public this(T value)
|
||||||
public this(T value)
|
|
||||||
{
|
{
|
||||||
mHasValue = true;
|
mHasValue = true;
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
public bool HasValue
|
public bool HasValue
|
||||||
{
|
{
|
||||||
get { return mHasValue; }
|
get { return mHasValue; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
public T Value
|
public T Value
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Debug.Assert(mHasValue, "Value cannot be retrieved on a null nullable.");
|
if (!mHasValue)
|
||||||
|
{
|
||||||
|
Debug.FatalError("Nullable object must have a value.");
|
||||||
|
}
|
||||||
|
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref T ValueRef
|
[Inline]
|
||||||
{
|
public ref T ValueRef
|
||||||
get mut
|
|
||||||
{
|
|
||||||
Debug.Assert(mHasValue, "Value cannot be retrieved on a null nullable.");
|
|
||||||
return ref mValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*public override bool Equals(object other)
|
|
||||||
{
|
{
|
||||||
if (other == null)
|
get mut
|
||||||
return mHasValue == false;
|
{
|
||||||
if (!(other is Nullable<T>))
|
if (!mHasValue)
|
||||||
return false;
|
{
|
||||||
|
Debug.FatalError("Nullable object must have a value.");
|
||||||
return Equals((Nullable<T>)other);
|
}
|
||||||
|
|
||||||
|
return ref mValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Equals(Nullable<T> other)
|
|
||||||
{
|
|
||||||
if (other.mHasValue != mHasValue)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (mHasValue == false)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return other.mValue.Equals(mValue);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*public override int GetHashCode()
|
|
||||||
{
|
|
||||||
if (!mHasValue)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return mValue.GetHashCode();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public T GetValueOrDefault()
|
public T GetValueOrDefault()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetValueOrDefault(T defaultValue)
|
public T GetValueOrDefault(T defaultmValue)
|
||||||
{
|
{
|
||||||
return mHasValue ? mValue : defaultValue;
|
return mHasValue ? mValue : defaultmValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ToString(String str)
|
public override void ToString(String str)
|
||||||
|
@ -87,16 +66,369 @@ namespace System
|
||||||
else
|
else
|
||||||
str.Clear();
|
str.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
public static implicit operator Nullable<T>(T value)
|
public static implicit operator Nullable<T>(T value)
|
||||||
{
|
{
|
||||||
return Nullable<T>(value);
|
return Nullable<T>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
public static explicit operator T(Nullable<T> value)
|
public static explicit operator T(Nullable<T> value)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.mHasValue, "Value cannot be retrieved on a null nullable.");
|
|
||||||
return value.mValue;
|
return value.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static bool operator==(Nullable<T> lhs, T rhs)
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T == TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther == T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T == TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue == rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T != TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue != rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther != T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs != rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T != TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue != rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T < TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther < T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T < TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue < rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T <= TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue <= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther <= T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs <= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T <= TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue <= rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator><TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T > TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue > rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator><TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther > T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs > rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T > TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue > rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T >= TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue >= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther >= T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs >= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T >= TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue >= rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(Nullable<T> lhs, TOther rhs) where int : operator T <=> TOther
|
||||||
|
{
|
||||||
|
return lhs.mValue <=> rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(TOther lhs, Nullable<T> rhs) where int : operator TOther <=> T
|
||||||
|
{
|
||||||
|
return lhs <=> rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where int : operator T <=> TOther where TOther : struct
|
||||||
|
{
|
||||||
|
return lhs.mValue <=> rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T + TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue + rhs);
|
||||||
|
}
|
||||||
|
public static TResult? operator+<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther + T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs + rhs.mValue);
|
||||||
|
}
|
||||||
|
public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T + TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue + rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther - T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs - rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T - TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue - rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T - TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue - rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther * T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs * rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T * TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue * rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T * TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue * rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther / T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs / rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T / TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue / rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T / TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue / rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther % T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs % rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T % TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue % rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T % TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue % rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ^ T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs ^ rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ^ TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue ^ rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ^ TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue ^ rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther & T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs & rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T & TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue & rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T & TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue & rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther | T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs | rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T | TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue | rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T | TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue | rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ?? T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs ?? rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ?? TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue ?? rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ?? TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue ?? rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther << T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs << rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T << TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue << rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T << TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue << rhs.mValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Nullable<T> : IHashable where T : IHashable
|
||||||
|
{
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
if (!mHasValue)
|
||||||
|
return 0;
|
||||||
|
return mValue.GetHashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
IDE/dist/BeefDbgVis.toml
vendored
4
IDE/dist/BeefDbgVis.toml
vendored
|
@ -231,8 +231,8 @@ Name = "[Count]"
|
||||||
Value = "mCount - mFreeCount"
|
Value = "mCount - mFreeCount"
|
||||||
[Type.Expand.DictionaryItems]
|
[Type.Expand.DictionaryItems]
|
||||||
Size = "mCount - mFreeCount"
|
Size = "mCount - mFreeCount"
|
||||||
Buckets = "&mBuckets.mFirstElement"
|
Buckets = "mBuckets"
|
||||||
Entries = "&mEntries.mFirstElement"
|
Entries = "mEntries"
|
||||||
Key = "mKey"
|
Key = "mKey"
|
||||||
Value = "mValue"
|
Value = "mValue"
|
||||||
Next = "mNext"
|
Next = "mNext"
|
||||||
|
|
|
@ -25,11 +25,56 @@ namespace System
|
||||||
static int operator<=>(Self lhs, Self rhs);
|
static int operator<=>(Self lhs, Self rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IOpComparable<TRight>
|
||||||
|
{
|
||||||
|
static int operator<=>(Self lhs, TRight rhs);
|
||||||
|
}
|
||||||
|
|
||||||
interface IOpAddable
|
interface IOpAddable
|
||||||
{
|
{
|
||||||
static Self operator+(Self lhs, Self rhs);
|
static Self operator+(Self lhs, Self rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IOpSubtractable
|
||||||
|
{
|
||||||
|
static Self operator-(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpMultipliable
|
||||||
|
{
|
||||||
|
static Self operator*(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpDividable
|
||||||
|
{
|
||||||
|
static Self operator/(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpBitwiseAndable
|
||||||
|
{
|
||||||
|
static Self operator&(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpBitwiseOrable
|
||||||
|
{
|
||||||
|
static Self operator|(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpExclusiveOrable
|
||||||
|
{
|
||||||
|
static Self operator^(Self lhs, Self rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpLeftShiftable
|
||||||
|
{
|
||||||
|
static Self operator^(Self lhs, int rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOpRightShiftable
|
||||||
|
{
|
||||||
|
static Self operator^(Self lhs, int rhs);
|
||||||
|
}
|
||||||
|
|
||||||
interface IOpNegatable
|
interface IOpNegatable
|
||||||
{
|
{
|
||||||
static Self operator-(Self value);
|
static Self operator-(Self value);
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Diagnostics;
|
||||||
|
|
||||||
namespace System
|
namespace System
|
||||||
{
|
{
|
||||||
public struct Nullable<T> where T : struct
|
struct Nullable<T> where T : struct
|
||||||
{
|
{
|
||||||
internal T mValue;
|
internal T mValue;
|
||||||
internal bool mHasValue;
|
internal bool mHasValue;
|
||||||
|
@ -49,35 +49,6 @@ namespace System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public override bool Equals(Object other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
return mHasValue == false;
|
|
||||||
if (!(other is Nullable<T>))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return Equals((Nullable<T>)other);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*bool Equals(Nullable<T> other)
|
|
||||||
{
|
|
||||||
if (other.mHasValue != mHasValue)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (mHasValue == false)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return other.mValue.Equals(mValue);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*public override int GetHashCode()
|
|
||||||
{
|
|
||||||
if (!mHasValue)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return mValue.GetHashCode();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public T GetValueOrDefault()
|
public T GetValueOrDefault()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
|
@ -96,16 +67,368 @@ namespace System
|
||||||
str.Clear();
|
str.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Inline]
|
[Inline]
|
||||||
public static implicit operator Nullable<T>(T value)
|
public static implicit operator Nullable<T>(T value)
|
||||||
{
|
{
|
||||||
return Nullable<T>(value);
|
return Nullable<T>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Inline]
|
[Inline]
|
||||||
public static explicit operator T(Nullable<T> value)
|
public static explicit operator T(Nullable<T> value)
|
||||||
{
|
{
|
||||||
return value.mValue;
|
return value.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static bool operator==(Nullable<T> lhs, T rhs)
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T == TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther == T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator==<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T == TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue == rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T != TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue != rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther != T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs != rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator!=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T != TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue != rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T < TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther < T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator< <TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T < TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue < rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T <= TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue <= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther <= T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs <= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator<=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T <= TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue <= rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator><TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T > TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue > rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator><TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther > T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs > rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T > TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue > rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T >= TOther
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return false;
|
||||||
|
return lhs.mValue >= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther >= T
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return false;
|
||||||
|
return lhs >= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator>=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T >= TOther where TOther : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
||||||
|
return lhs.mValue >= rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(Nullable<T> lhs, TOther rhs) where int : operator T <=> TOther
|
||||||
|
{
|
||||||
|
return lhs.mValue <=> rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(TOther lhs, Nullable<T> rhs) where int : operator TOther <=> T
|
||||||
|
{
|
||||||
|
return lhs <=> rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int operator<=><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where int : operator T <=> TOther where TOther : struct
|
||||||
|
{
|
||||||
|
return lhs.mValue <=> rhs.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T + TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue + rhs);
|
||||||
|
}
|
||||||
|
public static TResult? operator+<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther + T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs + rhs.mValue);
|
||||||
|
}
|
||||||
|
public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T + TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue + rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther - T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs - rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T - TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue - rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T - TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue - rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther * T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs * rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T * TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue * rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T * TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue * rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther / T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs / rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T / TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue / rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T / TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue / rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther % T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs % rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T % TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue % rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T % TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue % rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ^ T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs ^ rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ^ TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue ^ rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ^ TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue ^ rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther & T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs & rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T & TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue & rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T & TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue & rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther | T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs | rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T | TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue | rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T | TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue | rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ?? T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs ?? rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ?? TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue ?? rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ?? TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue ?? rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther << T where TResult : struct
|
||||||
|
{
|
||||||
|
if (!rhs.mHasValue) return null;
|
||||||
|
return .(lhs << rhs.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T << TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if (!lhs.mHasValue) return null;
|
||||||
|
return .(lhs.mValue << rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T << TOther where TResult : struct
|
||||||
|
{
|
||||||
|
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||||
|
return .(lhs.mValue << rhs.mValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Nullable<T> : IHashable where T : IHashable
|
||||||
|
{
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
if (!mHasValue)
|
||||||
|
return 0;
|
||||||
|
return mValue.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1997,7 +1997,7 @@ namespace IDE.ui
|
||||||
|
|
||||||
public bool ToggleComment()
|
public bool ToggleComment()
|
||||||
{
|
{
|
||||||
if (HasSelection())
|
if ((HasSelection()) && (mSelection.Value.Length > 1))
|
||||||
{
|
{
|
||||||
var startLineAndCol = CursorLineAndColumn ;
|
var startLineAndCol = CursorLineAndColumn ;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ BfContext::BfContext(BfCompiler* compiler) :
|
||||||
mLockModules = false;
|
mLockModules = false;
|
||||||
|
|
||||||
mCurTypeState = NULL;
|
mCurTypeState = NULL;
|
||||||
|
mCurConstraintState = NULL;
|
||||||
mResolvingVarField = false;
|
mResolvingVarField = false;
|
||||||
|
|
||||||
for (int i = 0; i < BfTypeCode_Length; i++)
|
for (int i = 0; i < BfTypeCode_Length; i++)
|
||||||
|
|
|
@ -272,6 +272,32 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BfConstraintState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BfGenericParamInstance* mGenericParamInstance;
|
||||||
|
BfType* mLeftType;
|
||||||
|
BfType* mRightType;
|
||||||
|
BfConstraintState* mPrevState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BfConstraintState()
|
||||||
|
{
|
||||||
|
mGenericParamInstance = NULL;
|
||||||
|
mLeftType = NULL;
|
||||||
|
mRightType = NULL;
|
||||||
|
mPrevState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const BfConstraintState& other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(mGenericParamInstance == other.mGenericParamInstance) &&
|
||||||
|
(mLeftType == other.mLeftType) &&
|
||||||
|
(mRightType == other.mRightType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class BfContext
|
class BfContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -279,6 +305,7 @@ public:
|
||||||
bool mDeleting;
|
bool mDeleting;
|
||||||
|
|
||||||
BfTypeState* mCurTypeState;
|
BfTypeState* mCurTypeState;
|
||||||
|
BfConstraintState* mCurConstraintState;
|
||||||
bool mResolvingVarField;
|
bool mResolvingVarField;
|
||||||
int mMappedObjectRevision;
|
int mMappedObjectRevision;
|
||||||
|
|
||||||
|
@ -364,7 +391,7 @@ public:
|
||||||
void SaveDeletingType(BfType* type);
|
void SaveDeletingType(BfType* type);
|
||||||
BfType* FindType(const StringImpl& typeName);
|
BfType* FindType(const StringImpl& typeName);
|
||||||
String TypeIdToString(int typeId);
|
String TypeIdToString(int typeId);
|
||||||
BfHotTypeData* GetHotTypeData(int typeId);
|
BfHotTypeData* GetHotTypeData(int typeId);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BfContext(BfCompiler* compiler);
|
BfContext(BfCompiler* compiler);
|
||||||
|
|
|
@ -1030,6 +1030,15 @@ bool BfMethodMatcher::InferFromGenericConstraints(BfGenericParamInstance* generi
|
||||||
if (rightType != NULL)
|
if (rightType != NULL)
|
||||||
rightType = mModule->FixIntUnknown(rightType);
|
rightType = mModule->FixIntUnknown(rightType);
|
||||||
|
|
||||||
|
BfConstraintState constraintSet;
|
||||||
|
constraintSet.mPrevState = mModule->mContext->mCurConstraintState;
|
||||||
|
constraintSet.mGenericParamInstance = genericParamInst;
|
||||||
|
constraintSet.mLeftType = leftType;
|
||||||
|
constraintSet.mRightType = rightType;
|
||||||
|
SetAndRestoreValue<BfConstraintState*> prevConstraintSet(mModule->mContext->mCurConstraintState, &constraintSet);
|
||||||
|
if (!mModule->CheckConstraintState(NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (checkOpConstraint.mBinaryOp != BfBinaryOp_None)
|
if (checkOpConstraint.mBinaryOp != BfBinaryOp_None)
|
||||||
{
|
{
|
||||||
BfExprEvaluator exprEvaluator(mModule);
|
BfExprEvaluator exprEvaluator(mModule);
|
||||||
|
@ -3374,14 +3383,14 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
||||||
return mModule->GetDefaultTypedValue(resolvedFieldType);
|
return mModule->GetDefaultTypedValue(resolvedFieldType);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTemporary = false;
|
bool isTemporary = target.IsTempAddr();
|
||||||
bool wantsLoadValue = false;
|
bool wantsLoadValue = false;
|
||||||
if ((field->mIsReadOnly) && ((mModule->mCurMethodInstance->mMethodDef->mMethodType != BfMethodType_Ctor) || (!target.IsThis())))
|
if ((field->mIsReadOnly) && ((mModule->mCurMethodInstance->mMethodDef->mMethodType != BfMethodType_Ctor) || (!target.IsThis())))
|
||||||
wantsLoadValue = true;
|
wantsLoadValue = true;
|
||||||
|
|
||||||
bool isComposite = target.mType->IsComposite();
|
bool isComposite = target.mType->IsComposite();
|
||||||
if ((isComposite) && (!target.mType->IsTypedPrimitive()) && (!target.IsAddr()))
|
if ((isComposite) && (!target.mType->IsTypedPrimitive()) && (!target.IsAddr()))
|
||||||
isTemporary = true;
|
isTemporary = true;
|
||||||
if ((isComposite) && (!target.IsAddr()))
|
if ((isComposite) && (!target.IsAddr()))
|
||||||
wantsLoadValue = true;
|
wantsLoadValue = true;
|
||||||
|
|
||||||
|
@ -4005,7 +4014,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return mModule->GetDefaultTypedValue(returnType, true, returnType->IsComposite() ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
|
auto val = mModule->GetDefaultTypedValue(returnType, true, methodInstance->HasStructRet() ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
|
||||||
|
if (val.mKind == BfTypedValueKind_Addr)
|
||||||
|
val.mKind = BfTypedValueKind_TempAddr;
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2955,6 +2955,11 @@ void BfIRBuilder::CreateTypeDefinition(BfType* type, bool forceDefine)
|
||||||
if (!typeInstance->IsTypedPrimitive())
|
if (!typeInstance->IsTypedPrimitive())
|
||||||
StructSetBody(MapTypeInst(typeInstance), irFieldTypes, isPacked || !isCRepr);
|
StructSetBody(MapTypeInst(typeInstance), irFieldTypes, isPacked || !isCRepr);
|
||||||
|
|
||||||
|
if (typeInstance->IsNullable())
|
||||||
|
{
|
||||||
|
BF_ASSERT(irFieldTypes.size() <= 3);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
|
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
|
||||||
{
|
{
|
||||||
auto fieldInstance = &fieldInstanceRef;
|
auto fieldInstance = &fieldInstanceRef;
|
||||||
|
|
|
@ -6691,7 +6691,16 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
|
||||||
rightType = ResolveGenericType(rightType, *methodGenericArgs);
|
rightType = ResolveGenericType(rightType, *methodGenericArgs);
|
||||||
if (rightType != NULL)
|
if (rightType != NULL)
|
||||||
rightType = FixIntUnknown(rightType);
|
rightType = FixIntUnknown(rightType);
|
||||||
|
|
||||||
|
BfConstraintState constraintSet;
|
||||||
|
constraintSet.mPrevState = mContext->mCurConstraintState;
|
||||||
|
constraintSet.mGenericParamInstance = genericParamInst;
|
||||||
|
constraintSet.mLeftType = leftType;
|
||||||
|
constraintSet.mRightType = rightType;
|
||||||
|
SetAndRestoreValue<BfConstraintState*> prevConstraintSet(mContext->mCurConstraintState, &constraintSet);
|
||||||
|
if (!CheckConstraintState(NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (checkOpConstraint.mBinaryOp != BfBinaryOp_None)
|
if (checkOpConstraint.mBinaryOp != BfBinaryOp_None)
|
||||||
{
|
{
|
||||||
BfExprEvaluator exprEvaluator(this);
|
BfExprEvaluator exprEvaluator(this);
|
||||||
|
@ -10585,10 +10594,9 @@ bool BfModule::CheckModifyValue(BfTypedValue& typedValue, BfAstNode* refNode, co
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typedValue.mKind == BfTypedValueKind_TempAddr)
|
if (typedValue.mKind == BfTypedValueKind_TempAddr)
|
||||||
{
|
{
|
||||||
Fail(StrFormat("Cannot %s value", modifyType), refNode);
|
Fail(StrFormat("Cannot %s temporary value", modifyType), refNode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14224,7 +14232,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
BfIRValue fieldAddr;
|
BfIRValue fieldAddr;
|
||||||
if (!mCurTypeInstance->IsTypedPrimitive())
|
if ((!mCurTypeInstance->IsTypedPrimitive()) && (!fieldInst->mResolvedType->IsVar()))
|
||||||
{
|
{
|
||||||
fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst->mDataIdx /*, fieldDef->mName*/);
|
fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst->mDataIdx /*, fieldDef->mName*/);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1443,8 +1443,7 @@ public:
|
||||||
void AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
|
void AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
|
||||||
BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false);
|
BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false);
|
||||||
void EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry);
|
void EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry);
|
||||||
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
||||||
bool DoCanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
|
||||||
bool CanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
bool CanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
||||||
bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting);
|
bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting);
|
||||||
BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, bool callDtor = true);
|
BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, bool callDtor = true);
|
||||||
|
@ -1458,7 +1457,7 @@ public:
|
||||||
void CleanupFileInstances();
|
void CleanupFileInstances();
|
||||||
void AssertErrorState();
|
void AssertErrorState();
|
||||||
void AssertParseErrorState();
|
void AssertParseErrorState();
|
||||||
void InitTypeInst(BfTypedValue typedValue, BfScopeData* scope, bool zeroMemory, BfIRValue dataSize);
|
void InitTypeInst(BfTypedValue typedValue, BfScopeData* scope, bool zeroMemory, BfIRValue dataSize);
|
||||||
BfIRValue AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTarget, BfType* type, BfIRValue sizeValue, BfIRValue alignValue, BfAllocFlags allocFlags/*bool zeroMemory, bool defaultToMalloc*/);
|
BfIRValue AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTarget, BfType* type, BfIRValue sizeValue, BfIRValue alignValue, BfAllocFlags allocFlags/*bool zeroMemory, bool defaultToMalloc*/);
|
||||||
BfIRValue GetMarkFuncPtr(BfType* type);
|
BfIRValue GetMarkFuncPtr(BfType* type);
|
||||||
BfIRValue GetDbgRawAllocData(BfType* type);
|
BfIRValue GetDbgRawAllocData(BfType* type);
|
||||||
|
@ -1542,6 +1541,7 @@ public:
|
||||||
bool BuildGenericParams(BfType* resolvedTypeRef);
|
bool BuildGenericParams(BfType* resolvedTypeRef);
|
||||||
bool ValidateGenericConstraints(BfTypeReference* typeRef, BfGenericTypeInstance* genericTypeInstance, bool ignoreErrors);
|
bool ValidateGenericConstraints(BfTypeReference* typeRef, BfGenericTypeInstance* genericTypeInstance, bool ignoreErrors);
|
||||||
bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter);
|
bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter);
|
||||||
|
bool CheckConstraintState(BfAstNode* refNode);
|
||||||
bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef);
|
bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef);
|
||||||
void CheckInjectNewRevision(BfTypeInstance* typeInstance);
|
void CheckInjectNewRevision(BfTypeInstance* typeInstance);
|
||||||
bool InitType(BfType* resolvedTypeRef, BfPopulateType populateType);
|
bool InitType(BfType* resolvedTypeRef, BfPopulateType populateType);
|
||||||
|
|
|
@ -275,6 +275,30 @@ bool BfModule::AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGeneri
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BfModule::CheckConstraintState(BfAstNode* refNode)
|
||||||
|
{
|
||||||
|
if (mContext->mCurConstraintState == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto checkState = mContext->mCurConstraintState->mPrevState;
|
||||||
|
while (checkState != NULL)
|
||||||
|
{
|
||||||
|
if (*checkState == *mContext->mCurConstraintState)
|
||||||
|
{
|
||||||
|
if (refNode != NULL)
|
||||||
|
{
|
||||||
|
Fail("Constraints cause circular operator invocations", refNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkState = checkState->mPrevState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool BfModule::ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef)
|
bool BfModule::ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef)
|
||||||
{
|
{
|
||||||
if (firstDeclaringTypeDef == secondDeclaringTypeDef)
|
if (firstDeclaringTypeDef == secondDeclaringTypeDef)
|
||||||
|
|
|
@ -4371,10 +4371,12 @@ BfTypeReference* BfReducer::DoCreateNamedTypeRef(BfIdentifierNode* identifierNod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArrayBracket)
|
BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefFlags createTypeRefFlags)
|
||||||
{
|
{
|
||||||
AssertCurrentNode(firstNode);
|
AssertCurrentNode(firstNode);
|
||||||
|
|
||||||
|
bool parseArrayBracket = (createTypeRefFlags & CreateTypeRefFlags_NoParseArrayBrackets) == 0;
|
||||||
|
|
||||||
auto identifierNode = BfNodeDynCast<BfIdentifierNode>(firstNode);
|
auto identifierNode = BfNodeDynCast<BfIdentifierNode>(firstNode);
|
||||||
if (identifierNode == NULL)
|
if (identifierNode == NULL)
|
||||||
{
|
{
|
||||||
|
@ -4475,7 +4477,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket);
|
auto elementType = CreateTypeRefAfter(tokenNode, createTypeRefFlags);
|
||||||
auto constTypeRef = mAlloc->Alloc<BfConstTypeRef>();
|
auto constTypeRef = mAlloc->Alloc<BfConstTypeRef>();
|
||||||
ReplaceNode(firstNode, constTypeRef);
|
ReplaceNode(firstNode, constTypeRef);
|
||||||
MEMBER_SET(constTypeRef, mConstToken, tokenNode);
|
MEMBER_SET(constTypeRef, mConstToken, tokenNode);
|
||||||
|
@ -4486,7 +4488,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra
|
||||||
else if (token == BfToken_Unsigned)
|
else if (token == BfToken_Unsigned)
|
||||||
{
|
{
|
||||||
BF_ASSERT(mCompatMode);
|
BF_ASSERT(mCompatMode);
|
||||||
auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket);
|
auto elementType = CreateTypeRefAfter(tokenNode, createTypeRefFlags);
|
||||||
|
|
||||||
BfTypeReference* rootElementParent = NULL;
|
BfTypeReference* rootElementParent = NULL;
|
||||||
auto rootElement = elementType;
|
auto rootElement = elementType;
|
||||||
|
@ -4525,7 +4527,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra
|
||||||
tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_LParen);
|
tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_LParen);
|
||||||
MEMBER_SET_CHECKED(retTypeTypeRef, mOpenParen, tokenNode);
|
MEMBER_SET_CHECKED(retTypeTypeRef, mOpenParen, tokenNode);
|
||||||
|
|
||||||
auto elementType = CreateTypeRefAfter(retTypeTypeRef, parseArrayBracket);
|
auto elementType = CreateTypeRefAfter(retTypeTypeRef, createTypeRefFlags);
|
||||||
MEMBER_SET_CHECKED(retTypeTypeRef, mElementType, elementType);
|
MEMBER_SET_CHECKED(retTypeTypeRef, mElementType, elementType);
|
||||||
|
|
||||||
tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_RParen);
|
tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_RParen);
|
||||||
|
@ -4811,32 +4813,6 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra
|
||||||
}
|
}
|
||||||
MoveNode(sizeExpr, arrayType);
|
MoveNode(sizeExpr, arrayType);
|
||||||
params.push_back(sizeExpr);
|
params.push_back(sizeExpr);
|
||||||
|
|
||||||
// if (params.size() == 0)
|
|
||||||
// {
|
|
||||||
// BfExpression* sizeExpr = CreateExpressionAfter(arrayType);
|
|
||||||
// if (sizeExpr == NULL)
|
|
||||||
// {
|
|
||||||
// hasFailed = true;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// MoveNode(sizeExpr, arrayType);
|
|
||||||
// params.push_back(sizeExpr);
|
|
||||||
// tokenNode = ExpectTokenAfter(arrayType, BfToken_RBracket);
|
|
||||||
// if (tokenNode == NULL)
|
|
||||||
// {
|
|
||||||
// hasFailed = true;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// MoveNode(tokenNode, arrayType);
|
|
||||||
// arrayType->mCloseBracket = tokenNode;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// FailAfter("Either ',' or ']' expected", arrayType);
|
|
||||||
// return arrayType;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4954,8 +4930,34 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra
|
||||||
return typeRef;
|
return typeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayBracket)
|
BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, CreateTypeRefFlags createTypeRefFlags)
|
||||||
{
|
{
|
||||||
|
if ((createTypeRefFlags & CreateTypeRefFlags_SafeGenericParse) != 0)
|
||||||
|
{
|
||||||
|
createTypeRefFlags = (CreateTypeRefFlags)(createTypeRefFlags & ~CreateTypeRefFlags_SafeGenericParse);
|
||||||
|
|
||||||
|
int outEndNode = -1;
|
||||||
|
bool isTypeRef = IsTypeReference(firstNode, BfToken_None, &outEndNode);
|
||||||
|
|
||||||
|
if ((!isTypeRef) && (outEndNode != -1))
|
||||||
|
{
|
||||||
|
for (int checkIdx = outEndNode - 1; checkIdx > mVisitorPos.mReadPos; checkIdx--)
|
||||||
|
{
|
||||||
|
auto checkNode = mVisitorPos.Get(checkIdx);
|
||||||
|
if (auto checkToken = BfNodeDynCast<BfTokenNode>(checkNode))
|
||||||
|
{
|
||||||
|
if (checkToken->mToken == BfToken_LChevron)
|
||||||
|
{
|
||||||
|
checkToken->mToken = BfToken_Bar;
|
||||||
|
auto typeRef = CreateTypeRef(firstNode, createTypeRefFlags);
|
||||||
|
checkToken->mToken = BfToken_LChevron;
|
||||||
|
return typeRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(firstNode))
|
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(firstNode))
|
||||||
{
|
{
|
||||||
BfToken token = tokenNode->GetToken();
|
BfToken token = tokenNode->GetToken();
|
||||||
|
@ -4963,7 +4965,7 @@ BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayB
|
||||||
{
|
{
|
||||||
auto nextNode = mVisitorPos.GetNext();
|
auto nextNode = mVisitorPos.GetNext();
|
||||||
mVisitorPos.MoveNext();
|
mVisitorPos.MoveNext();
|
||||||
auto typeRef = DoCreateTypeRef(nextNode, parseArrayBracket);
|
auto typeRef = DoCreateTypeRef(nextNode, createTypeRefFlags);
|
||||||
if (typeRef == NULL)
|
if (typeRef == NULL)
|
||||||
{
|
{
|
||||||
mVisitorPos.mReadPos--;
|
mVisitorPos.mReadPos--;
|
||||||
|
@ -4975,13 +4977,13 @@ BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayB
|
||||||
else if ((token == BfToken_In) || (token == BfToken_As))
|
else if ((token == BfToken_In) || (token == BfToken_As))
|
||||||
{
|
{
|
||||||
// This is mostly to allow a partially typed 'int' to be parsed as 'in' to make autocomplete nicer
|
// This is mostly to allow a partially typed 'int' to be parsed as 'in' to make autocomplete nicer
|
||||||
return CreateTypeRef(ReplaceTokenStarter(firstNode), parseArrayBracket);
|
return CreateTypeRef(ReplaceTokenStarter(firstNode), createTypeRefFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DoCreateTypeRef(firstNode, parseArrayBracket);
|
return DoCreateTypeRef(firstNode, createTypeRefFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypeReference* BfReducer::CreateTypeRefAfter(BfAstNode* astNode, bool parseArrayBracket)
|
BfTypeReference* BfReducer::CreateTypeRefAfter(BfAstNode* astNode, CreateTypeRefFlags createTypeRefFlags)
|
||||||
{
|
{
|
||||||
AssertCurrentNode(astNode);
|
AssertCurrentNode(astNode);
|
||||||
auto nextNode = mVisitorPos.GetNext();
|
auto nextNode = mVisitorPos.GetNext();
|
||||||
|
@ -4993,7 +4995,7 @@ BfTypeReference* BfReducer::CreateTypeRefAfter(BfAstNode* astNode, bool parseArr
|
||||||
|
|
||||||
mVisitorPos.MoveNext();
|
mVisitorPos.MoveNext();
|
||||||
int startPos = mVisitorPos.mReadPos;
|
int startPos = mVisitorPos.mReadPos;
|
||||||
BfTypeReference* typeRef = CreateTypeRef(nextNode, parseArrayBracket);
|
BfTypeReference* typeRef = CreateTypeRef(nextNode, createTypeRefFlags);
|
||||||
if (typeRef == NULL)
|
if (typeRef == NULL)
|
||||||
{
|
{
|
||||||
BF_ASSERT(mVisitorPos.mReadPos == startPos);
|
BF_ASSERT(mVisitorPos.mReadPos == startPos);
|
||||||
|
@ -9010,18 +9012,31 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration(
|
||||||
|
|
||||||
auto opToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
|
auto opToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
|
||||||
if (opToken == NULL)
|
if (opToken == NULL)
|
||||||
{
|
{
|
||||||
auto typeRef = CreateTypeRefAfter(opConstraint);
|
auto typeRef = CreateTypeRefAfter(opConstraint, BfReducer::CreateTypeRefFlags_SafeGenericParse);
|
||||||
if (typeRef == NULL)
|
if (typeRef == NULL)
|
||||||
break;
|
break;
|
||||||
MEMBER_SET(opConstraint, mLeftType, typeRef);
|
MEMBER_SET(opConstraint, mLeftType, typeRef);
|
||||||
opToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
|
opToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
|
||||||
|
|
||||||
|
if (opToken == NULL)
|
||||||
|
{
|
||||||
|
if (auto pointerTypeRef = BfNodeDynCast<BfPointerTypeRef>(typeRef))
|
||||||
|
{
|
||||||
|
MEMBER_SET(opConstraint, mLeftType, pointerTypeRef->mElementType);
|
||||||
|
opToken = pointerTypeRef->mStarNode;
|
||||||
|
MEMBER_SET(opConstraint, mOpToken, opToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opToken == NULL)
|
if (opConstraint->mOpToken == NULL)
|
||||||
break;
|
{
|
||||||
MEMBER_SET(opConstraint, mOpToken, opToken);
|
if (opToken == NULL)
|
||||||
mVisitorPos.MoveNext();
|
break;
|
||||||
|
MEMBER_SET(opConstraint, mOpToken, opToken);
|
||||||
|
mVisitorPos.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
auto typeRef = CreateTypeRefAfter(opConstraint);
|
auto typeRef = CreateTypeRefAfter(opConstraint);
|
||||||
if (typeRef == NULL)
|
if (typeRef == NULL)
|
||||||
|
|
|
@ -40,6 +40,13 @@ public:
|
||||||
CreateStmtFlags_To_CreateExprFlags_Mask = 1
|
CreateStmtFlags_To_CreateExprFlags_Mask = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CreateTypeRefFlags
|
||||||
|
{
|
||||||
|
CreateTypeRefFlags_None,
|
||||||
|
CreateTypeRefFlags_NoParseArrayBrackets = 1,
|
||||||
|
CreateTypeRefFlags_SafeGenericParse = 2
|
||||||
|
};
|
||||||
|
|
||||||
struct BfVisitorPos
|
struct BfVisitorPos
|
||||||
{
|
{
|
||||||
BfBlock* mParent;
|
BfBlock* mParent;
|
||||||
|
@ -204,9 +211,9 @@ public:
|
||||||
bool IsLocalMethod(BfAstNode* nameNode);
|
bool IsLocalMethod(BfAstNode* nameNode);
|
||||||
int QualifiedBacktrack(BfAstNode* endNode, int checkIdx, bool* outHadChevrons = NULL); // Backtracks to dot token
|
int QualifiedBacktrack(BfAstNode* endNode, int checkIdx, bool* outHadChevrons = NULL); // Backtracks to dot token
|
||||||
BfTypeReference* DoCreateNamedTypeRef(BfIdentifierNode* identifierNode);
|
BfTypeReference* DoCreateNamedTypeRef(BfIdentifierNode* identifierNode);
|
||||||
BfTypeReference* DoCreateTypeRef(BfAstNode* identifierNode, bool parseArrayBracket = true);
|
BfTypeReference* DoCreateTypeRef(BfAstNode* identifierNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None);
|
||||||
BfTypeReference* CreateTypeRef(BfAstNode* identifierNode, bool parseArrayBracket = true);
|
BfTypeReference* CreateTypeRef(BfAstNode* identifierNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None);
|
||||||
BfTypeReference* CreateTypeRefAfter(BfAstNode* astNode, bool parseArrayBracket = true);
|
BfTypeReference* CreateTypeRefAfter(BfAstNode* astNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None);
|
||||||
BfTypeReference* CreateRefTypeRef(BfTypeReference* elementType, BfTokenNode* refToken);
|
BfTypeReference* CreateRefTypeRef(BfTypeReference* elementType, BfTokenNode* refToken);
|
||||||
BfTypeReference* CreateConstTypeRef(BfTypeReference* elementType, BfTokenNode* refToken);
|
BfTypeReference* CreateConstTypeRef(BfTypeReference* elementType, BfTokenNode* refToken);
|
||||||
bool ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayImpl<BfParameterDeclaration*>* params, SizedArrayImpl<BfTokenNode*>* commas, bool alwaysIncludeBlock = false);
|
bool ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayImpl<BfParameterDeclaration*>* params, SizedArrayImpl<BfTokenNode*>* commas, bool alwaysIncludeBlock = false);
|
||||||
|
|
22
IDEHelper/Tests/src/Nullable.bf
Normal file
22
IDEHelper/Tests/src/Nullable.bf
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
class Nullable
|
||||||
|
{
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestPrimitives()
|
||||||
|
{
|
||||||
|
float? fn = 9.0f;
|
||||||
|
int? intn = 100;
|
||||||
|
int? intn2 = null;
|
||||||
|
|
||||||
|
let fn2 = fn + intn;
|
||||||
|
Test.Assert(fn2 == 109);
|
||||||
|
|
||||||
|
let fn3 = fn + intn2;
|
||||||
|
Test.Assert(fn3 == null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue