File: DataFlow\LocalStateLattice.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;
using ILLink.Shared.DataFlow;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FlowAnalysis;
 
namespace ILLink.RoslynAnalyzer.DataFlow
{
	public readonly struct LocalKey : IEquatable<LocalKey>
	{
		readonly ILocalSymbol? Local;
 
		readonly CaptureId? CaptureId;
 
		public LocalKey (ILocalSymbol symbol) => (Local, CaptureId) = (symbol, null);
 
		public LocalKey (CaptureId captureId) => (Local, CaptureId) = (null, captureId);
 
		public bool Equals (LocalKey other) => SymbolEqualityComparer.Default.Equals (Local, other.Local) &&
			(CaptureId?.Equals (other.CaptureId) ?? other.CaptureId == null);
 
		public override bool Equals (object obj)
			=> obj is LocalKey inst && Equals (inst);
 
		public override int GetHashCode ()
			=> CaptureId is null ? SymbolEqualityComparer.Default.GetHashCode (Local) : CaptureId.GetHashCode ();
 
		public override string ToString ()
		{
			if (Local != null)
				return Local.ToString ();
			return $"capture {CaptureId.GetHashCode ()}";
		}
	}
 
	public struct LocalState<TValue> : IEquatable<LocalState<TValue>>
		where TValue : IEquatable<TValue>
	{
		public DefaultValueDictionary<LocalKey, TValue> Dictionary;
 
		// Stores any operations which are captured by reference in a FlowCaptureOperation.
		// Only stores captures which are assigned through. Captures of the values of operations
		// are tracked as part of the dictionary of values, keyed by LocalKey.
		public DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> CapturedReferences;
 
		public LocalState (TValue defaultValue)
			: this (new DefaultValueDictionary<LocalKey, TValue> (defaultValue),
				new DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> (default (ValueSet<CapturedReferenceValue>)))
		{
		}
 
		public LocalState (DefaultValueDictionary<LocalKey, TValue> dictionary, DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> capturedReferences)
		{
			Dictionary = dictionary;
			CapturedReferences = capturedReferences;
		}
 
		public LocalState (DefaultValueDictionary<LocalKey, TValue> dictionary)
			: this (dictionary, new DefaultValueDictionary<CaptureId, ValueSet<CapturedReferenceValue>> (default (ValueSet<CapturedReferenceValue>)))
		{
		}
 
		public bool Equals (LocalState<TValue> other) => Dictionary.Equals (other.Dictionary);
 
		public override bool Equals (object obj)
			=> obj is LocalState<TValue> inst && Equals (inst);
 
		public TValue Get (LocalKey key) => Dictionary.Get (key);
 
		public override int GetHashCode ()
			=> throw new NotImplementedException ();
 
		public void Set (LocalKey key, TValue value) => Dictionary.Set (key, value);
 
		public override string ToString () => Dictionary.ToString ();
	}
 
	// Wrapper struct exists purely to substitute a concrete LocalKey for TKey of DictionaryLattice
	public readonly struct LocalStateLattice<TValue, TValueLattice> : ILattice<LocalState<TValue>>
		where TValue : struct, IEquatable<TValue>
		where TValueLattice : ILattice<TValue>
	{
		public readonly DictionaryLattice<LocalKey, TValue, TValueLattice> Lattice;
		public readonly DictionaryLattice<CaptureId, ValueSet<CapturedReferenceValue>, ValueSetLattice<CapturedReferenceValue>> CapturedReferenceLattice;
 
		public LocalStateLattice (TValueLattice valueLattice)
		{
			Lattice = new DictionaryLattice<LocalKey, TValue, TValueLattice> (valueLattice);
			CapturedReferenceLattice = new DictionaryLattice<CaptureId, ValueSet<CapturedReferenceValue>, ValueSetLattice<CapturedReferenceValue>> (default (ValueSetLattice<CapturedReferenceValue>));
			Top = new (Lattice.Top);
		}
 
		public LocalState<TValue> Top { get; }
 
		public LocalState<TValue> Meet (LocalState<TValue> left, LocalState<TValue> right)
		{
			var dictionary = Lattice.Meet (left.Dictionary, right.Dictionary);
			var capturedProperties = CapturedReferenceLattice.Meet (left.CapturedReferences, right.CapturedReferences);
			return new LocalState<TValue> (dictionary, capturedProperties);
		}
	}
}