diff --git a/BeefLibs/corlib/src/Collections/Generic/Dictionary.bf b/BeefLibs/corlib/src/Collections/Generic/Dictionary.bf index 8a143642..d8abd37a 100644 --- a/BeefLibs/corlib/src/Collections/Generic/Dictionary.bf +++ b/BeefLibs/corlib/src/Collections/Generic/Dictionary.bf @@ -414,8 +414,7 @@ namespace System.Collections.Generic int_cosize* newBuckets = new int_cosize[newSize]*; for (int_cosize i = 0; i < newSize; i++) newBuckets[i] = -1; Entry* newEntries = new Entry[newSize]*; - //mEntries.CopyTo(newEntries, 0, 0, mCount); - Internal.MemCpy(newEntries, mEntries, mCount * sizeof(Entry), alignof(Entry)); + Internal.MemCpy(newEntries, mEntries, mCount * strideof(Entry), alignof(Entry)); if (forceNewHashCodes) { diff --git a/BeefLibs/corlib/src/Nullable.bf b/BeefLibs/corlib/src/Nullable.bf index 47afc62f..75f4e64c 100644 --- a/BeefLibs/corlib/src/Nullable.bf +++ b/BeefLibs/corlib/src/Nullable.bf @@ -1,83 +1,62 @@ using System.Reflection; using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Diagnostics; namespace System { - public struct Nullable where T : struct + struct Nullable where T : struct { - #region Sync with runtime code - internal T mValue; + internal T mValue; internal bool mHasValue; - #endregion - - public this(T value) + + public this(T value) { mHasValue = true; mValue = value; } - + + [Inline] public bool HasValue { get { return mHasValue; } } - + + [Inline] public T Value { get { - Debug.Assert(mHasValue, "Value cannot be retrieved on a null nullable."); + if (!mHasValue) + { + Debug.FatalError("Nullable object must have a value."); + } + return mValue; } } - 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) + [Inline] + public ref T ValueRef { - if (other == null) - return mHasValue == false; - if (!(other is Nullable)) - return false; - - return Equals((Nullable)other); + get mut + { + if (!mHasValue) + { + Debug.FatalError("Nullable object must have a value."); + } + + return ref mValue; + } } - bool Equals(Nullable 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() { 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) @@ -87,16 +66,369 @@ namespace System else str.Clear(); } - + + [Inline] public static implicit operator Nullable(T value) { return Nullable(value); } - + + [Inline] public static explicit operator T(Nullable value) { - Debug.Assert(value.mHasValue, "Value cannot be retrieved on a null nullable."); return value.mValue; } + + [Inline] + public static bool operator==(Nullable lhs, T rhs) + { + if (!lhs.mHasValue) return false; + return lhs.mValue == rhs; + } + + /// + + public static bool operator==(Nullable lhs, TOther rhs) where bool : operator T == TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue == rhs; + } + + public static bool operator==(TOther lhs, Nullable rhs) where bool : operator TOther == T + { + if (!rhs.mHasValue) return false; + return lhs == rhs; + } + + public static bool operator==(Nullable lhs, Nullable 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!=(Nullable lhs, TOther rhs) where bool : operator T != TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue != rhs; + } + + public static bool operator!=(TOther lhs, Nullable rhs) where bool : operator TOther != T + { + if (!rhs.mHasValue) return false; + return lhs != rhs; + } + + public static bool operator!=(Nullable lhs, Nullable 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< (Nullable lhs, TOther rhs) where bool : operator T < TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue < rhs; + } + + public static bool operator< (TOther lhs, Nullable rhs) where bool : operator TOther < T + { + if (!rhs.mHasValue) return false; + return lhs < rhs; + } + + public static bool operator< (Nullable lhs, Nullable 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<=(Nullable lhs, TOther rhs) where bool : operator T <= TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue <= rhs; + } + + public static bool operator<=(TOther lhs, Nullable rhs) where bool : operator TOther <= T + { + if (!rhs.mHasValue) return false; + return lhs <= rhs; + } + + public static bool operator<=(Nullable lhs, Nullable 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>(Nullable lhs, TOther rhs) where bool : operator T > TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue > rhs; + } + + public static bool operator>(TOther lhs, Nullable rhs) where bool : operator TOther > T + { + if (!rhs.mHasValue) return false; + return lhs > rhs; + } + + public static bool operator>(Nullable lhs, Nullable 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>=(Nullable lhs, TOther rhs) where bool : operator T >= TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue >= rhs; + } + + public static bool operator>=(TOther lhs, Nullable rhs) where bool : operator TOther >= T + { + if (!rhs.mHasValue) return false; + return lhs >= rhs; + } + + public static bool operator>=(Nullable lhs, Nullable 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<=>(Nullable lhs, TOther rhs) where int : operator T <=> TOther + { + return lhs.mValue <=> rhs; + } + + public static int operator<=>(TOther lhs, Nullable rhs) where int : operator TOther <=> T + { + return lhs <=> rhs; + } + + public static int operator<=>(Nullable lhs, Nullable rhs) where int : operator T <=> TOther where TOther : struct + { + return lhs.mValue <=> rhs.mValue; + } + + /// + + public static TResult? operator+(Nullable 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 lhs, Nullable rhs) where TResult = operator TOther + T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs + rhs.mValue); + } + public static TResult? operator+(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther - T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs - rhs.mValue); + } + + public static TResult? operator-(Nullable lhs, TOther rhs) where TResult = operator T - TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue - rhs); + } + + public static TResult? operator-(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther * T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs * rhs.mValue); + } + + public static TResult? operator*(Nullable lhs, TOther rhs) where TResult = operator T * TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue * rhs); + } + + public static TResult? operator*(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther / T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs / rhs.mValue); + } + + public static TResult? operator/(Nullable lhs, TOther rhs) where TResult = operator T / TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue / rhs); + } + + public static TResult? operator/(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther % T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs % rhs.mValue); + } + + public static TResult? operator%(Nullable lhs, TOther rhs) where TResult = operator T % TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue % rhs); + } + + public static TResult? operator%(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther ^ T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs ^ rhs.mValue); + } + + public static TResult? operator^(Nullable lhs, TOther rhs) where TResult = operator T ^ TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue ^ rhs); + } + + public static TResult? operator^(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther & T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs & rhs.mValue); + } + + public static TResult? operator&(Nullable lhs, TOther rhs) where TResult = operator T & TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue & rhs); + } + + public static TResult? operator&(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther | T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs | rhs.mValue); + } + + public static TResult? operator|(Nullable lhs, TOther rhs) where TResult = operator T | TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue | rhs); + } + + public static TResult? operator|(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther ?? T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs ?? rhs.mValue); + } + + public static TResult? operator??(Nullable lhs, TOther rhs) where TResult = operator T ?? TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue ?? rhs); + } + + public static TResult? operator??(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther << T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs << rhs.mValue); + } + + public static TResult? operator<< (Nullable lhs, TOther rhs) where TResult = operator T << TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue << rhs); + } + + public static TResult? operator<< (Nullable lhs, Nullable 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 : IHashable where T : IHashable + { + public int GetHashCode() + { + if (!mHasValue) + return 0; + return mValue.GetHashCode(); + } } } diff --git a/IDE/dist/BeefDbgVis.toml b/IDE/dist/BeefDbgVis.toml index e77d311a..51fd15d2 100644 --- a/IDE/dist/BeefDbgVis.toml +++ b/IDE/dist/BeefDbgVis.toml @@ -231,8 +231,8 @@ Name = "[Count]" Value = "mCount - mFreeCount" [Type.Expand.DictionaryItems] Size = "mCount - mFreeCount" -Buckets = "&mBuckets.mFirstElement" -Entries = "&mEntries.mFirstElement" +Buckets = "mBuckets" +Entries = "mEntries" Key = "mKey" Value = "mValue" Next = "mNext" diff --git a/IDE/mintest/minlib/src/System/IComparable.bf b/IDE/mintest/minlib/src/System/IComparable.bf index 5a3bc21d..cc4201d9 100644 --- a/IDE/mintest/minlib/src/System/IComparable.bf +++ b/IDE/mintest/minlib/src/System/IComparable.bf @@ -25,11 +25,56 @@ namespace System static int operator<=>(Self lhs, Self rhs); } + interface IOpComparable + { + static int operator<=>(Self lhs, TRight rhs); + } + interface IOpAddable { 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 { static Self operator-(Self value); diff --git a/IDE/mintest/minlib/src/System/Nullable.bf b/IDE/mintest/minlib/src/System/Nullable.bf index 6638b3f3..bb04ff28 100644 --- a/IDE/mintest/minlib/src/System/Nullable.bf +++ b/IDE/mintest/minlib/src/System/Nullable.bf @@ -4,7 +4,7 @@ using System.Diagnostics; namespace System { - public struct Nullable where T : struct + struct Nullable where T : struct { internal T mValue; 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)) - return false; - - return Equals((Nullable)other); - }*/ - - /*bool Equals(Nullable 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() { return mValue; @@ -96,16 +67,368 @@ namespace System str.Clear(); } - //[Inline] + [Inline] public static implicit operator Nullable(T value) { return Nullable(value); } - //[Inline] + [Inline] public static explicit operator T(Nullable value) { return value.mValue; } + + [Inline] + public static bool operator==(Nullable lhs, T rhs) + { + if (!lhs.mHasValue) return false; + return lhs.mValue == rhs; + } + + /// + + public static bool operator==(Nullable lhs, TOther rhs) where bool : operator T == TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue == rhs; + } + + public static bool operator==(TOther lhs, Nullable rhs) where bool : operator TOther == T + { + if (!rhs.mHasValue) return false; + return lhs == rhs; + } + + public static bool operator==(Nullable lhs, Nullable 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!=(Nullable lhs, TOther rhs) where bool : operator T != TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue != rhs; + } + + public static bool operator!=(TOther lhs, Nullable rhs) where bool : operator TOther != T + { + if (!rhs.mHasValue) return false; + return lhs != rhs; + } + + public static bool operator!=(Nullable lhs, Nullable 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< (Nullable lhs, TOther rhs) where bool : operator T < TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue < rhs; + } + + public static bool operator< (TOther lhs, Nullable rhs) where bool : operator TOther < T + { + if (!rhs.mHasValue) return false; + return lhs < rhs; + } + + public static bool operator< (Nullable lhs, Nullable 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<=(Nullable lhs, TOther rhs) where bool : operator T <= TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue <= rhs; + } + + public static bool operator<=(TOther lhs, Nullable rhs) where bool : operator TOther <= T + { + if (!rhs.mHasValue) return false; + return lhs <= rhs; + } + + public static bool operator<=(Nullable lhs, Nullable 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>(Nullable lhs, TOther rhs) where bool : operator T > TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue > rhs; + } + + public static bool operator>(TOther lhs, Nullable rhs) where bool : operator TOther > T + { + if (!rhs.mHasValue) return false; + return lhs > rhs; + } + + public static bool operator>(Nullable lhs, Nullable 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>=(Nullable lhs, TOther rhs) where bool : operator T >= TOther + { + if (!lhs.mHasValue) return false; + return lhs.mValue >= rhs; + } + + public static bool operator>=(TOther lhs, Nullable rhs) where bool : operator TOther >= T + { + if (!rhs.mHasValue) return false; + return lhs >= rhs; + } + + public static bool operator>=(Nullable lhs, Nullable 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<=>(Nullable lhs, TOther rhs) where int : operator T <=> TOther + { + return lhs.mValue <=> rhs; + } + + public static int operator<=>(TOther lhs, Nullable rhs) where int : operator TOther <=> T + { + return lhs <=> rhs; + } + + public static int operator<=>(Nullable lhs, Nullable rhs) where int : operator T <=> TOther where TOther : struct + { + return lhs.mValue <=> rhs.mValue; + } + + /// + + public static TResult? operator+(Nullable 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 lhs, Nullable rhs) where TResult = operator TOther + T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs + rhs.mValue); + } + public static TResult? operator+(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther - T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs - rhs.mValue); + } + + public static TResult? operator-(Nullable lhs, TOther rhs) where TResult = operator T - TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue - rhs); + } + + public static TResult? operator-(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther * T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs * rhs.mValue); + } + + public static TResult? operator*(Nullable lhs, TOther rhs) where TResult = operator T * TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue * rhs); + } + + public static TResult? operator*(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther / T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs / rhs.mValue); + } + + public static TResult? operator/(Nullable lhs, TOther rhs) where TResult = operator T / TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue / rhs); + } + + public static TResult? operator/(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther % T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs % rhs.mValue); + } + + public static TResult? operator%(Nullable lhs, TOther rhs) where TResult = operator T % TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue % rhs); + } + + public static TResult? operator%(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther ^ T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs ^ rhs.mValue); + } + + public static TResult? operator^(Nullable lhs, TOther rhs) where TResult = operator T ^ TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue ^ rhs); + } + + public static TResult? operator^(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther & T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs & rhs.mValue); + } + + public static TResult? operator&(Nullable lhs, TOther rhs) where TResult = operator T & TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue & rhs); + } + + public static TResult? operator&(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther | T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs | rhs.mValue); + } + + public static TResult? operator|(Nullable lhs, TOther rhs) where TResult = operator T | TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue | rhs); + } + + public static TResult? operator|(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther ?? T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs ?? rhs.mValue); + } + + public static TResult? operator??(Nullable lhs, TOther rhs) where TResult = operator T ?? TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue ?? rhs); + } + + public static TResult? operator??(Nullable lhs, Nullable 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 lhs, Nullable rhs) where TResult = operator TOther << T where TResult : struct + { + if (!rhs.mHasValue) return null; + return .(lhs << rhs.mValue); + } + + public static TResult? operator<< (Nullable lhs, TOther rhs) where TResult = operator T << TOther where TResult : struct + { + if (!lhs.mHasValue) return null; + return .(lhs.mValue << rhs); + } + + public static TResult? operator<< (Nullable lhs, Nullable 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 : IHashable where T : IHashable + { + public int GetHashCode() + { + if (!mHasValue) + return 0; + return mValue.GetHashCode(); + } + } } diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 7dad75f3..67ede778 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -1997,7 +1997,7 @@ namespace IDE.ui public bool ToggleComment() { - if (HasSelection()) + if ((HasSelection()) && (mSelection.Value.Length > 1)) { var startLineAndCol = CursorLineAndColumn ; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 7ef7318c..8b62c4c0 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -46,6 +46,7 @@ BfContext::BfContext(BfCompiler* compiler) : mLockModules = false; mCurTypeState = NULL; + mCurConstraintState = NULL; mResolvingVarField = false; for (int i = 0; i < BfTypeCode_Length; i++) diff --git a/IDEHelper/Compiler/BfContext.h b/IDEHelper/Compiler/BfContext.h index d0fe8f9b..8f0043fa 100644 --- a/IDEHelper/Compiler/BfContext.h +++ b/IDEHelper/Compiler/BfContext.h @@ -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 { public: @@ -279,6 +305,7 @@ public: bool mDeleting; BfTypeState* mCurTypeState; + BfConstraintState* mCurConstraintState; bool mResolvingVarField; int mMappedObjectRevision; @@ -364,7 +391,7 @@ public: void SaveDeletingType(BfType* type); BfType* FindType(const StringImpl& typeName); String TypeIdToString(int typeId); - BfHotTypeData* GetHotTypeData(int typeId); + BfHotTypeData* GetHotTypeData(int typeId); public: BfContext(BfCompiler* compiler); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 71bf25d6..1c61a8b3 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -1030,6 +1030,15 @@ bool BfMethodMatcher::InferFromGenericConstraints(BfGenericParamInstance* generi if (rightType != NULL) rightType = mModule->FixIntUnknown(rightType); + BfConstraintState constraintSet; + constraintSet.mPrevState = mModule->mContext->mCurConstraintState; + constraintSet.mGenericParamInstance = genericParamInst; + constraintSet.mLeftType = leftType; + constraintSet.mRightType = rightType; + SetAndRestoreValue prevConstraintSet(mModule->mContext->mCurConstraintState, &constraintSet); + if (!mModule->CheckConstraintState(NULL)) + return false; + if (checkOpConstraint.mBinaryOp != BfBinaryOp_None) { BfExprEvaluator exprEvaluator(mModule); @@ -3374,14 +3383,14 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar return mModule->GetDefaultTypedValue(resolvedFieldType); } - bool isTemporary = false; + bool isTemporary = target.IsTempAddr(); bool wantsLoadValue = false; if ((field->mIsReadOnly) && ((mModule->mCurMethodInstance->mMethodDef->mMethodType != BfMethodType_Ctor) || (!target.IsThis()))) wantsLoadValue = true; bool isComposite = target.mType->IsComposite(); if ((isComposite) && (!target.mType->IsTypedPrimitive()) && (!target.IsAddr())) - isTemporary = true; + isTemporary = true; if ((isComposite) && (!target.IsAddr())) wantsLoadValue = true; @@ -4005,7 +4014,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV } 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; } }; diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index b3a302f9..f3767c02 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2955,6 +2955,11 @@ void BfIRBuilder::CreateTypeDefinition(BfType* type, bool forceDefine) if (!typeInstance->IsTypedPrimitive()) StructSetBody(MapTypeInst(typeInstance), irFieldTypes, isPacked || !isCRepr); + if (typeInstance->IsNullable()) + { + BF_ASSERT(irFieldTypes.size() <= 3); + } + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) { auto fieldInstance = &fieldInstanceRef; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 70061fb7..1722055a 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -6691,7 +6691,16 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS rightType = ResolveGenericType(rightType, *methodGenericArgs); if (rightType != NULL) rightType = FixIntUnknown(rightType); - + + BfConstraintState constraintSet; + constraintSet.mPrevState = mContext->mCurConstraintState; + constraintSet.mGenericParamInstance = genericParamInst; + constraintSet.mLeftType = leftType; + constraintSet.mRightType = rightType; + SetAndRestoreValue prevConstraintSet(mContext->mCurConstraintState, &constraintSet); + if (!CheckConstraintState(NULL)) + return false; + if (checkOpConstraint.mBinaryOp != BfBinaryOp_None) { BfExprEvaluator exprEvaluator(this); @@ -10585,10 +10594,9 @@ bool BfModule::CheckModifyValue(BfTypedValue& typedValue, BfAstNode* refNode, co return false; } - if (typedValue.mKind == BfTypedValueKind_TempAddr) { - Fail(StrFormat("Cannot %s value", modifyType), refNode); + Fail(StrFormat("Cannot %s temporary value", modifyType), refNode); return false; } @@ -14224,7 +14232,7 @@ void BfModule::EmitCtorBody(bool& skipBody) } BfIRValue fieldAddr; - if (!mCurTypeInstance->IsTypedPrimitive()) + if ((!mCurTypeInstance->IsTypedPrimitive()) && (!fieldInst->mResolvedType->IsVar())) { fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst->mDataIdx /*, fieldDef->mName*/); } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 734a5122..74b88393 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1443,8 +1443,7 @@ public: void AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array* captures = NULL); BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false); void EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry); - void EmitDeferredCallProcessor(SLIList& callEntries, BfIRValue callTail); - bool DoCanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None); + void EmitDeferredCallProcessor(SLIList& callEntries, BfIRValue callTail); bool CanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None); 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); @@ -1458,7 +1457,7 @@ public: void CleanupFileInstances(); void AssertErrorState(); 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 GetMarkFuncPtr(BfType* type); BfIRValue GetDbgRawAllocData(BfType* type); @@ -1542,6 +1541,7 @@ public: bool BuildGenericParams(BfType* resolvedTypeRef); bool ValidateGenericConstraints(BfTypeReference* typeRef, BfGenericTypeInstance* genericTypeInstance, bool ignoreErrors); bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter); + bool CheckConstraintState(BfAstNode* refNode); bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef); void CheckInjectNewRevision(BfTypeInstance* typeInstance); bool InitType(BfType* resolvedTypeRef, BfPopulateType populateType); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 151e8559..0ff2afef 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -275,6 +275,30 @@ bool BfModule::AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGeneri 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) { if (firstDeclaringTypeDef == secondDeclaringTypeDef) diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index e0545314..e9beed45 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -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); + bool parseArrayBracket = (createTypeRefFlags & CreateTypeRefFlags_NoParseArrayBrackets) == 0; + auto identifierNode = BfNodeDynCast(firstNode); if (identifierNode == NULL) { @@ -4475,7 +4477,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra } else { - auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket); + auto elementType = CreateTypeRefAfter(tokenNode, createTypeRefFlags); auto constTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, constTypeRef); MEMBER_SET(constTypeRef, mConstToken, tokenNode); @@ -4486,7 +4488,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra else if (token == BfToken_Unsigned) { BF_ASSERT(mCompatMode); - auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket); + auto elementType = CreateTypeRefAfter(tokenNode, createTypeRefFlags); BfTypeReference* rootElementParent = NULL; auto rootElement = elementType; @@ -4525,7 +4527,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_LParen); MEMBER_SET_CHECKED(retTypeTypeRef, mOpenParen, tokenNode); - auto elementType = CreateTypeRefAfter(retTypeTypeRef, parseArrayBracket); + auto elementType = CreateTypeRefAfter(retTypeTypeRef, createTypeRefFlags); MEMBER_SET_CHECKED(retTypeTypeRef, mElementType, elementType); tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_RParen); @@ -4811,32 +4813,6 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArra } MoveNode(sizeExpr, arrayType); 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; } -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(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(firstNode)) { BfToken token = tokenNode->GetToken(); @@ -4963,7 +4965,7 @@ BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayB { auto nextNode = mVisitorPos.GetNext(); mVisitorPos.MoveNext(); - auto typeRef = DoCreateTypeRef(nextNode, parseArrayBracket); + auto typeRef = DoCreateTypeRef(nextNode, createTypeRefFlags); if (typeRef == NULL) { mVisitorPos.mReadPos--; @@ -4975,13 +4977,13 @@ BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayB 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 - 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); auto nextNode = mVisitorPos.GetNext(); @@ -4993,7 +4995,7 @@ BfTypeReference* BfReducer::CreateTypeRefAfter(BfAstNode* astNode, bool parseArr mVisitorPos.MoveNext(); int startPos = mVisitorPos.mReadPos; - BfTypeReference* typeRef = CreateTypeRef(nextNode, parseArrayBracket); + BfTypeReference* typeRef = CreateTypeRef(nextNode, createTypeRefFlags); if (typeRef == NULL) { BF_ASSERT(mVisitorPos.mReadPos == startPos); @@ -9010,18 +9012,31 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( auto opToken = BfNodeDynCast(mVisitorPos.GetNext()); if (opToken == NULL) - { - auto typeRef = CreateTypeRefAfter(opConstraint); + { + auto typeRef = CreateTypeRefAfter(opConstraint, BfReducer::CreateTypeRefFlags_SafeGenericParse); if (typeRef == NULL) break; MEMBER_SET(opConstraint, mLeftType, typeRef); opToken = BfNodeDynCast(mVisitorPos.GetNext()); + + if (opToken == NULL) + { + if (auto pointerTypeRef = BfNodeDynCast(typeRef)) + { + MEMBER_SET(opConstraint, mLeftType, pointerTypeRef->mElementType); + opToken = pointerTypeRef->mStarNode; + MEMBER_SET(opConstraint, mOpToken, opToken); + } + } } - if (opToken == NULL) - break; - MEMBER_SET(opConstraint, mOpToken, opToken); - mVisitorPos.MoveNext(); + if (opConstraint->mOpToken == NULL) + { + if (opToken == NULL) + break; + MEMBER_SET(opConstraint, mOpToken, opToken); + mVisitorPos.MoveNext(); + } auto typeRef = CreateTypeRefAfter(opConstraint); if (typeRef == NULL) diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index b903e19d..5c25ed11 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -40,6 +40,13 @@ public: CreateStmtFlags_To_CreateExprFlags_Mask = 1 }; + enum CreateTypeRefFlags + { + CreateTypeRefFlags_None, + CreateTypeRefFlags_NoParseArrayBrackets = 1, + CreateTypeRefFlags_SafeGenericParse = 2 + }; + struct BfVisitorPos { BfBlock* mParent; @@ -204,9 +211,9 @@ public: bool IsLocalMethod(BfAstNode* nameNode); int QualifiedBacktrack(BfAstNode* endNode, int checkIdx, bool* outHadChevrons = NULL); // Backtracks to dot token BfTypeReference* DoCreateNamedTypeRef(BfIdentifierNode* identifierNode); - BfTypeReference* DoCreateTypeRef(BfAstNode* identifierNode, bool parseArrayBracket = true); - BfTypeReference* CreateTypeRef(BfAstNode* identifierNode, bool parseArrayBracket = true); - BfTypeReference* CreateTypeRefAfter(BfAstNode* astNode, bool parseArrayBracket = true); + BfTypeReference* DoCreateTypeRef(BfAstNode* identifierNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None); + BfTypeReference* CreateTypeRef(BfAstNode* identifierNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None); + BfTypeReference* CreateTypeRefAfter(BfAstNode* astNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None); BfTypeReference* CreateRefTypeRef(BfTypeReference* elementType, BfTokenNode* refToken); BfTypeReference* CreateConstTypeRef(BfTypeReference* elementType, BfTokenNode* refToken); bool ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayImpl* params, SizedArrayImpl* commas, bool alwaysIncludeBlock = false); diff --git a/IDEHelper/Tests/src/Nullable.bf b/IDEHelper/Tests/src/Nullable.bf new file mode 100644 index 00000000..ea6f04b8 --- /dev/null +++ b/IDEHelper/Tests/src/Nullable.bf @@ -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); + } + } +}