// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; // This is needed due to NativeAOT which doesn't enable nullable globally yet #nullable enable namespace ILLink.Shared.DataFlow { // Wrapper for Nullable<T> which implements IEquatable so that this may // be used as a lattice value. Nullable types can't satisfy interface constraints; // see for example https://learn.microsoft.com/dotnet/csharp/misc/cs0313. public struct Maybe<T> : IEquatable<Maybe<T>>, IDeepCopyValue<Maybe<T>> where T : struct, IEquatable<T> { public T? MaybeValue; public Maybe(T value) => MaybeValue = value; public bool Equals(Maybe<T> other) => MaybeValue?.Equals(other.MaybeValue) ?? other.MaybeValue == null; public override bool Equals(object? obj) => obj is Maybe<T> other && Equals(other); public override int GetHashCode() => MaybeValue?.GetHashCode() ?? 0; public Maybe<T> DeepCopy() { if (MaybeValue is not T value) return default; if (value is IDeepCopyValue<T> copyValue) return new(copyValue.DeepCopy()); return new(value); } public static bool operator ==(Maybe<T> left, Maybe<T> right) => left.Equals(right); public static bool operator !=(Maybe<T> left, Maybe<T> right) => !(left == right); } public struct MaybeLattice<T, TValueLattice> : ILattice<Maybe<T>> where T : struct, IEquatable<T> where TValueLattice : ILattice<T> { public readonly TValueLattice ValueLattice; public MaybeLattice(TValueLattice valueLattice) { ValueLattice = valueLattice; Top = default; } public Maybe<T> Top { get; } public Maybe<T> Meet(Maybe<T> left, Maybe<T> right) { if (left.MaybeValue is not T leftValue) return right.DeepCopy(); if (right.MaybeValue is not T rightValue) return left.DeepCopy(); return new Maybe<T>(ValueLattice.Meet(leftValue, rightValue)); } } }