File: TrimAnalysis\ArrayValue.cs
Web Access
Project: src\src\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj (ILLink.RoslynAnalyzer)
// 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.Collections.Generic;
using ILLink.Shared.DataFlow;
using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
 
namespace ILLink.Shared.TrimAnalysis
{
	internal partial record ArrayValue
	{
		public readonly Dictionary<int, MultiValue> IndexValues;
 
		public static MultiValue Create (MultiValue size)
		{
			MultiValue result = MultiValueLattice.Top;
			foreach (var sizeValue in size.AsEnumerable ()) {
				result = MultiValueLattice.Meet (result, new MultiValue (new ArrayValue (sizeValue)));
			}
 
			return result;
		}
 
		public static MultiValue Create (int size) => Create (new ConstIntValue (size));
 
		ArrayValue (SingleValue size)
		{
			Size = size;
			IndexValues = new Dictionary<int, MultiValue> ();
		}
 
		public partial bool TryGetValueByIndex (int index, out MultiValue value)
		{
			if (IndexValues.TryGetValue (index, out value))
				return true;
 
			value = default;
			return false;
		}
 
		public override int GetHashCode ()
		{
			return HashUtils.Combine (GetType ().GetHashCode (), Size);
		}
 
		public bool Equals (ArrayValue? otherArr)
		{
			if (otherArr == null)
				return false;
 
			bool equals = Size.Equals (otherArr.Size);
			equals &= IndexValues.Count == otherArr.IndexValues.Count;
			if (!equals)
				return false;
 
			// Here we rely on the assumption that we can't store mutable values in arrays. The only mutable value
			// which we currently support are array values, but those are not allowed in an array (to avoid complexity).
			// As such we can rely on the values to be immutable, and thus if the counts are equal
			// then the arrays are equal if items from one can be directly found in the other.
			foreach (var kvp in IndexValues)
				if (!otherArr.IndexValues.TryGetValue (kvp.Key, out MultiValue value) || !kvp.Value.Equals (value))
					return false;
 
			return true;
		}
 
		// Lattice Meet() is supposed to copy values, so we need to make a deep copy since ArrayValue is mutable through IndexValues
		public override SingleValue DeepCopy ()
		{
			var newArray = new ArrayValue (Size);
			foreach (var kvp in IndexValues) {
#if DEBUG
				// Since it's possible to store a reference to array as one of its own elements
				// simple deep copy could lead to endless recursion.
				// So instead we simply disallow arrays as element values completely - and treat that case as "too complex to analyze".
				foreach (SingleValue v in kvp.Value.AsEnumerable ()) {
					System.Diagnostics.Debug.Assert (v is not ArrayValue);
				}
#endif
 
				newArray.IndexValues.Add (kvp.Key, kvp.Value.DeepCopy ());
			}
 
			return newArray;
		}
	}
}