internal class FSharpTypeParameterOfMethod()

in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/DeclaredElement/FSharpTypeParameterOfMethod.cs [18:152]


  internal class FSharpTypeParameterOfMethod([NotNull] IFunction method, [NotNull] string name, int index)
    : FSharpDeclaredElementBase, ITypeParameter
  {
    [NotNull] public readonly IFunction Method = method;

    public override DeclaredElementType GetElementType() =>
      CLRDeclaredElementType.TYPE_PARAMETER;

    public override string ShortName { get; } = name;

    public override bool IsValid() => Method.IsValid();
    public override IPsiModule Module => Method.Module;
    public override IPsiServices GetPsiServices() => Method.GetPsiServices();

    public override ITypeElement GetContainingType() => null;
    public override ITypeMember GetContainingTypeMember() => Method;

    public IList<ITypeParameter> TypeParameters => EmptyList<ITypeParameter>.Instance;
    public int TypeParametersCount => 0;
    public override ISubstitution IdSubstitution => EmptySubstitution.INSTANCE;

    public IClrTypeName GetClrName() => EmptyClrTypeName.Instance;
    public IList<IDeclaredType> GetSuperTypes() => SharedImplUtil.GetTypeParameterSuperTypes(this, IsValueType, TypeConstraints);
    public IList<ITypeElement> GetSuperTypeElements() => GetSuperTypes().ToTypeElements();

    public IEnumerable<ITypeMember> GetMembers() => EmptyList<ITypeMember>.InstanceList;
    public MemberPresenceFlag GetMemberPresenceFlag() => MemberPresenceFlag.NONE;

    public INamespace GetContainingNamespace() =>
      Method.ContainingType?.GetContainingNamespace() ??
      Module.GetSymbolScope(false).GlobalNamespace;

    public bool HasMemberWithName(string shortName, bool ignoreCase) => false;

    public IPsiSourceFile GetSingleOrDefaultSourceFile() => null;

    public IList<ITypeElement> NestedTypes => EmptyList<ITypeElement>.InstanceList;
    public IEnumerable<IField> Constants => EmptyList<IField>.Instance;
    public IEnumerable<IField> Fields => EmptyList<IField>.Instance;
    public IEnumerable<IConstructor> Constructors => EmptyList<IConstructor>.Instance;
    public IEnumerable<IOperator> Operators => EmptyList<IOperator>.Instance;
    public IEnumerable<IMethod> Methods => EmptyList<IMethod>.Instance;
    public IEnumerable<IProperty> Properties => EmptyList<IProperty>.Instance;
    public IEnumerable<IEvent> Events => EmptyList<IEvent>.Instance;
    public IEnumerable<string> MemberNames => EmptyList<string>.InstanceList;

    public TypeParameterNullability Nullability => TypeParameterNullability.Unknown;

    public TypeParameterNullability GetNullability(ISubstitution explicitInheritorSubstitution) =>
      TypeParameterNullability.Unknown;

    public int Index { get; } = index;
    public TypeParameterVariance Variance => TypeParameterVariance.INVARIANT;

    [CanBeNull]
    private FSharpGenericParameter GetFcsParameter()
    {
      if (!(Method is IFSharpTypeMember {ContainingType: { } typeElement, Symbol: FSharpMemberOrFunctionOrValue mfv})) 
        return null;

      var index = Index + typeElement.TypeParametersCount;
      var mfvTypeParameters = mfv.GenericParameters;
      return mfvTypeParameters.Count > index
        ? mfvTypeParameters[index]
        : null;
    }

    private IEnumerable<FSharpGenericParameterConstraint> FcsConstraints =>
        GetFcsParameter()?.Constraints ?? EmptyList<FSharpGenericParameterConstraint>.Instance;

    public bool IsValueType =>
      FcsConstraints.Any(constraint => constraint.IsNonNullableValueTypeConstraint);

    public bool IsReferenceType =>
      FcsConstraints.Any(constraint => constraint.IsReferenceTypeConstraint || constraint.IsSupportsNullConstraint);

    public bool IsUnmanagedType =>
      FcsConstraints.Any(constraint => constraint.IsUnmanagedConstraint);

    public bool HasDefaultConstructor =>
      FcsConstraints.Any(constraint => constraint.IsRequiresDefaultConstructorConstraint);

    public bool IsNotNullableValueOrReferenceType => false;

    public bool AllowsByRefLikeType => false;

    public bool HasTypeConstraints =>
      FcsConstraints.Any(constraint => constraint.IsCoercesToConstraint);

    public IList<IType> TypeConstraints =>
      FcsConstraints
        .SelectNotNull(constraint =>
          constraint.IsCoercesToConstraint ? constraint.CoercesToTarget.MapType(AllTypeParameters, Module) : null)
        .ToIList();

    private IList<ITypeParameter> AllTypeParameters =>
      Method is IFSharpTypeMember typeMember ? typeMember.AllTypeParameters : EmptyList<ITypeParameter>.Instance;

    public TypeParameterConstraintFlags Constraints
    {
      get
      {
        var result = TypeParameterConstraintFlags.None;
        foreach (var fcsConstraint in FcsConstraints)
        {
          if (fcsConstraint.IsReferenceTypeConstraint || fcsConstraint.IsSupportsNullConstraint)
            result |= TypeParameterConstraintFlags.ReferenceType;

          else if (fcsConstraint.IsNonNullableValueTypeConstraint)
            result |= TypeParameterConstraintFlags.ValueType;

          else if (fcsConstraint.IsRequiresDefaultConstructorConstraint)
            result |= TypeParameterConstraintFlags.Constructor;

          else if (fcsConstraint.IsUnmanagedConstraint)
            result |= TypeParameterConstraintFlags.Unmanaged;
        }

        return result;
      }
    }

    public NullableAnnotation NullableAnnotation => NullableAnnotation.Unknown;

    public IParametersOwner OwnerFunction => Method;
    public IMethod OwnerMethod => (IMethod) Method;
    public ITypeParametersOwner Owner => Method as ITypeParametersOwner;
    public ITypeElement OwnerType => Method.ContainingType;

    public override bool Equals(object obj) =>
      obj is FSharpTypeParameterOfMethod other &&
      ReferenceEquals(Method, other.Method) && Index == other.Index;

    public override int GetHashCode() => Index;
  }