Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type constrains #44

Merged
merged 7 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,96 @@ public partial class Person
return TestAndVerify(source);
}

[Fact]
public Task ClassWithNotNullConstraint()
{
var source = @"
[Reactive]
public partial class Cache<TKey, TValue>
where TKey : notnull
where TValue : class
{
public partial TValue? Value { get; set; }
public partial TKey Key { get; set; }
}";

return TestAndVerify(source);
}

[Fact]
public Task ClassWithMultipleComplexConstraints()
{
var source = @"
[Reactive]
public partial class AdvancedCache<T, TKey, TValue>
where T : class, IDisposable
where TKey : notnull
where TValue : struct, IComparable<TValue>
{
public partial T? Instance { get; set; }
public partial TKey Key { get; set; }
public partial TValue Value { get; set; }
}";

return TestAndVerify(source);
}

[Fact]
public Task ClassWithNullableReferenceConstraint()
{
var source = @"
[Reactive]
public partial class Container<T>
where T : class?
{
public partial T? Value { get; set; }
}";

return TestAndVerify(source);
}

[Fact]
public Task ClassWithUnmanagedConstraint()
{
var source = @"
[Reactive]
public partial class UnmanagedContainer<T>
where T : unmanaged
{
public partial T Value { get; set; }
}";

return TestAndVerify(source);
}

[Fact]
public Task AllPossibleConstraints()
{
var source = @"
public interface ITestInterface { }
public class BaseClass { }

[Reactive]
public partial class ConstraintsTest<T1, T2, T3, T4, T5, T6, T7>
where T1 : class, ITestInterface, new() // Reference type + interface + constructor
where T2 : struct, IComparable<T2> // Value type + interface with self
where T3 : notnull // Non-null constraint
where T4 : unmanaged // Unmanaged constraint
where T5 : BaseClass // Base class constraint
where T6 : T1 // Another type parameter constraint
where T7 : class? // Nullable reference type constraint
{
public partial T1? Property1 { get; set; }
public partial T2 Property2 { get; set; }
public partial T3 Property3 { get; set; }
public partial T4 Property4 { get; set; }
public partial T5? Property5 { get; set; }
public partial T6? Property6 { get; set; }
public partial T7? Property7 { get; set; }
}";

return TestAndVerify(source);
}
/* TODO:
[Fact]
public Task ReadOnlyPropertyTest()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
{
Sources: [
{
FileName: ConstraintsTest.INPC.g.cs,
Source:
// <auto-generated/>
#nullable enable

using System.ComponentModel;
using System.Runtime.CompilerServices;

public partial class ConstraintsTest<T1, T2, T3, T4, T5, T6, T7> : INotifyPropertyChanged where T1 : class, global::ITestInterface, new() where T2 : struct, IComparable<T2> where T3 : notnull where T4 : unmanaged, struct where T5 : global::BaseClass where T6 : T1 where T7 : class?
{
public event PropertyChangedEventHandler? PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(this, args);
}
}

},
{
FileName: ConstraintsTest.ReactiveProperties.g.cs,
Source:
// <auto-generated/>
#nullable enable

using System.ComponentModel;
using System.Runtime.CompilerServices;

/// <summary>
/// A partial class implementation for ConstraintsTest{T1, T2, T3, T4, T5, T6, T7}.
/// </summary>
public partial class ConstraintsTest<T1, T2, T3, T4, T5, T6, T7> where T1 : class, global::ITestInterface, new() where T2 : struct, IComparable<T2> where T3 : notnull where T4 : unmanaged, struct where T5 : global::BaseClass where T6 : T1 where T7 : class?
{
private static readonly PropertyChangedEventArgs _property1ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property1));
private static readonly PropertyChangedEventArgs _property2ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property2));
private static readonly PropertyChangedEventArgs _property3ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property3));
private static readonly PropertyChangedEventArgs _property4ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property4));
private static readonly PropertyChangedEventArgs _property5ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property5));
private static readonly PropertyChangedEventArgs _property6ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property6));
private static readonly PropertyChangedEventArgs _property7ChangedEventArgs = new PropertyChangedEventArgs(nameof(Property7));

public partial T1? Property1
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property1ChangedEventArgs);
}
}
}

public partial T2 Property2
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property2ChangedEventArgs);
}
}
}

public partial T3 Property3
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property3ChangedEventArgs);
}
}
}

public partial T4 Property4
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property4ChangedEventArgs);
}
}
}

public partial T5? Property5
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property5ChangedEventArgs);
}
}
}

public partial T6? Property6
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property6ChangedEventArgs);
}
}
}

public partial T7? Property7
{
get => field;
set
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(_property7ChangedEventArgs);
}
}
}
}

},
{
FileName: IgnoreReactiveAttribute.g.cs,
Source:
// <auto-generated/>
using System;

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
sealed class IgnoreReactiveAttribute : Attribute
{
public IgnoreReactiveAttribute() { }
}
},
{
FileName: ReactiveAttribute.g.cs,
Source:
// <auto-generated/>
using System;

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
sealed class ReactiveAttribute : Attribute
{
public ReactiveAttribute() { }
}
}
],
Diagnostics: null
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ sealed class ReactiveAttribute : Attribute
using System.ComponentModel;
using System.Runtime.CompilerServices;

public partial class TestClass<T, U> : INotifyPropertyChanged where T : class, IDisposable where U : struct, IComparable<U>
public partial class TestClass<T, U> : INotifyPropertyChanged where T : class?, IDisposable where U : struct, IComparable<U>
{
public event PropertyChangedEventHandler? PropertyChanged;

Expand Down Expand Up @@ -61,7 +61,7 @@ using System.Runtime.CompilerServices;
/// <summary>
/// A partial class implementation for TestClass{T, U}.
/// </summary>
public partial class TestClass<T, U> where T : class, IDisposable where U : struct, IComparable<U>
public partial class TestClass<T, U> where T : class?, IDisposable where U : struct, IComparable<U>
{
private static readonly PropertyChangedEventArgs _nullableRefChangedEventArgs = new PropertyChangedEventArgs(nameof(NullableRef));
private static readonly PropertyChangedEventArgs _nullableStructChangedEventArgs = new PropertyChangedEventArgs(nameof(NullableStruct));
Expand Down
Loading
Loading