Closed albertwoo closed 1 year ago
I believe the reason is because that Panel
implements IEquatable<Panel>
and VirtualizingPanel
implements IEquatable<VirtulizingPanel>
.
Since 'T
must satisfy :> Panel
for class A
the constraint solver figures that IEquatable<Panel>
should equal IEquatable<VirtualizingPanel>
and this is where the error message actually comes from.
So the behavior is correct, because VirtualizingPanel
does not satisfy this constraint, but the error message is quite confusing because the user doesn't know why the 2 types should be equal.
We should probably extend the error message with more context that would explain what's going on.
Minimal repro:
open System
type MyClass() =
member this.x = 1
interface IEquatable<MyClass> with
member this.Equals _ = false
type MySubClass() =
inherit MyClass()
interface IEquatable<MySubClass> with
member this.Equals _ = false
type A<'T when 'T :> MyClass>() =
class end
type B<'T when 'T :> MySubClass>() =
inherit A<'T>()
inherit A<'T>();;
------------^^^^^
stdin(19,13): error FS0001: The type 'MyClass' does not match the type 'MySubClass'
@0101 I think it is not message confusing. There are two reasons:
using System;
class MyClass : IEquatable
class MySubClass : MyClass, IEquatable
class A
class B
@albertwoo I guess you are right, it should probably accept any derived class.
This of course generalises to any such hierarchy based on an instance of the curiously recurring template pattern
type ISprintable<'T> =
abstract member Print : format:'T -> unit
type BaseClass() =
interface ISprintable<BaseClass> with
member this.Print t = printfn "%A" t
type Derived() =
inherit BaseClass()
interface ISprintable<Derived> with
member this.Print t = printfn "%A" t
type A<'T when 'T :> BaseClass>() =
class
end
type B<'T when 'T :> Derived>() =
inherit A<'T>()
which results in
inherit A<'T>();;
----------^^^^^
stdin(18,11): error FS0001: The type 'BaseClass' does not match the type 'Derived'
and not just the particular case of IEquatable<'T>
Strangely this works when using 2 generic parameters for B (provided by the same real type at instantiation), maybe this might give a hint on where the issue is. Can also act as a workaround for the time being ;; @albertwoo and @SteveGilham .
type ISprintable<'T> =
abstract member Print : format:'T -> unit
type BaseClass() =
interface ISprintable<BaseClass> with
member this.Print t = printfn "%A" t
type Derived() =
inherit BaseClass()
interface ISprintable<Derived> with
member this.Print t = printfn "%A" t
type A<'T when 'T :> BaseClass>() =
class
end
type B<'T,'U when 'T :> Derived and 'U:> BaseClass>() =
inherit A<'U>()
let giveMeA = new A<BaseClass>()
let giveMeB = new B<Derived,Derived>()
Seeing more trough it, this is a duplicate of https://github.com/dotnet/fsharp/issues/12206 . And is covered by this (not implemented) lang suggestion https://github.com/fsharp/fslang-suggestions/issues/255
Please provide a succinct description of the issue.
Repro steps
Repo to reproduce: https://github.com/albertwoo/FSharpInheritIssue/blob/c805f56a2fad1e0313a09e85695e88c2bfef77f6/Program.fs#L10
For other types this kind of inheritance is ok, but it looks like the Xaml panel or control have some special thing which cause fsharp compiler cannot infer that.
Expected behavior
Should repot no error.
Actual behavior
Provide a description of the actual behaviour observed.
Known workarounds
None
Related information
Provide any related information (optional):