1
0
Fork 0
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:
Brian Fiete 2019-11-21 08:23:18 -08:00
parent 59233cc996
commit 88adb3a1cd
16 changed files with 963 additions and 143 deletions

View file

@ -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)
{ {

View file

@ -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();
}
} }
} }

View file

@ -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"

View file

@ -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);

View file

@ -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();
}
}
} }

View file

@ -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 ;

View file

@ -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++)

View file

@ -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);

View file

@ -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;
} }
}; };

View file

@ -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;

View file

@ -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*/);
} }

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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);

View 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);
}
}
}