Repository navigation
Statically resolved type parameters don't propagate correctly, and hashed typenames like ^?9104 in unjust compile error #3508
Description
Activity
- changed the title
[-]Statically resolved type parameters don't propagate correctly, nasty unresolvable and unnecessary compile error: FS0001: A type parameter is missing a constraint 'when ^source : (static member op_Explicit : ^source -> ^?9104)'[/-][+]Statically resolved type parameters don't propagate correctly, and hashed typenames in compile error, seemingly impossible to understand or resolve[/+]on Aug 26, 2017 - changed the title
[-]Statically resolved type parameters don't propagate correctly, and hashed typenames in compile error, seemingly impossible to understand or resolve[/-][+]Statically resolved type parameters don't propagate correctly, and hashed typenames like ^?9104 in compile error[/+]on Aug 26, 2017 - changed the title
[-]Statically resolved type parameters don't propagate correctly, and hashed typenames like ^?9104 in compile error[/-][+]Statically resolved type parameters don't propagate correctly, and hashed typenames like ^?9104 in unjust compile error[/+]on Aug 26, 2017 @abelbraaksma Is there a repro without using
op_Explicitconstraints? thanks- addedImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.
on Aug 29, 2017 @dsyme, yes, it happens with basically any method. But perhaps more likely with
op_Explicitbecause that is usually used to be able to create an explicit cast (or, in other words, a member that has a different return type but the same parameters, which I believe is not allowed with any other operator, exceptop_Implicit).Example with op_Implicit:
type MyByte = MyByte of byte with static member MinValue = MyByte Byte.MinValue static member op_Implicit (MyByte x): int64 = int64 x static member op_Implicit (MyByte x): double = double x let inline isWithinMinMaxRange< ^b, ^a when ^b: comparison and ^a: comparison and ^b: (static member MinValue: ^b) and ^b : (static member op_Implicit: ^b -> ^a) > (value: ^a) = let minRange = ((^b) : (static member MinValue: ^b) ()) let cast v = (^b : (static member op_Implicit: ^b -> ^a) v) value > cast minRange // Does not compile, FS0001 and FS0043 on the last line let inline test< ^source, ^value when ^source: comparison and ^value: comparison and ^source: (static member MinValue: ^source) and ^source : (static member op_Implicit: ^source -> ^value) > (v: ^value) = isWithinMinMaxRange< ^source, ^value> v // error FS001 and FS0043 shown here with same textError:
error FS0001: A type parameter is missing a constraint 'when ^source : (static member op_Implicit : ^source -> ^?9809)'
error FS0043: A type parameter is missing a constraint 'when ^source : (static member op_Implicit : ^source -> ^?9809)'Example with a regular method (this code, however, is deliberately wrong, but it shows the error is faulty, or at the very least hard to understand):
type MyByte = MyByte of byte with static member MinValue = MyByte Byte.MinValue static member Foo (MyByte x): int64 = int64 x let inline isWithinMinMaxRange< ^b, ^a when ^b: comparison and ^a: comparison and ^b: (static member MinValue: ^b) and ^b : (static member Foo: ^b -> ^a) > (value: ^a) = let minRange = ((^b) : (static member MinValue: ^b) ()) let cast v = (^b : (static member Foo: ^b -> ^a) v) value > cast minRange // Does not compile, FS0001 and FS0043 on the last line let inline test< ^source, ^value when ^source: comparison and ^value: comparison and ^source: (static member MinValue: ^source)> (v: ^value) = isWithinMinMaxRange< ^source, ^value> vError:
error FS0001: A type parameter is missing a constraint 'when ^source : (static member Foo : ^source -> ^?9796)'
error FS0043: A type parameter is missing a constraint 'when ^source : (static member Foo : ^source -> ^?9796)'Of course, in the latter example, the member constraint is actually missing in the declaration of
test. However, it shows that a strange/wrong error is shown.It helps perhaps to show what I tried to achieve. I wanted to create a generic function with statically resolved type parameters, that can do a range check (and some other checks, removed for brevity) on a given type. Just some ducktyping, essentially. But for ease of use, I also hoped to be able to parameterize only the source type, as the target type would be known by the compiler from its argument.
Here's what I thought ought to work, the original idea (note the missing type declarations on the declaration of
test):type MyByte = MyByte of byte with static member MinValue = MyByte Byte.MinValue static member op_Explicit (MyByte x): int64 = int64 x static member op_Explicit (MyByte x): double = double x let inline isWithinMinMaxRange< ^b, ^a when ^b: comparison and ^a: comparison and ^b: (static member MinValue: ^b) and (^b) : (static member op_Explicit: ^b -> ^a) > (value: ^a) = let minRange = ((^b) : (static member MinValue: ^b) ()) let cast v = (( ^b) : (static member op_Explicit: ^b -> ^a) v) value > cast minRange let inline test v = isWithinMinMaxRange<MyByte, _> vI think this code should compile, but it throws a compile error on the last line:
error FS0043: The type 'MyByte' does not support a conversion to the type ''a'
Which made add such method (a dummy to do a conversion to an unknown target type), which ultimately led to #3509 (crash of FSC). I think, still, that the code above is valid and that the FS0043 error should not be raised.
I have meanwhile found a workaround:
Since such code is only possible with using either
op_Explicitorop_Implicit(because of limitations on return type variance), I noticed that, even if you only need a conversion in one direction (type^bto^ain this example), you must use theorsyntax with both types to get it to work, as in(^a or ^b) .....So, given the same example, this works:
type MyByte = MyByte of byte with static member MinValue = MyByte Byte.MinValue static member op_Explicit (MyByte x): int64 = int64 x static member op_Explicit (MyByte x): double = double x let inline isWithinMinMaxRange< ^b, ^a when ^b: comparison and ^a: comparison and ^b: (static member MinValue: ^b) and (^a or ^b) : (static member op_Explicit: ^b -> ^a) > (value: ^a) = let minRange = ((^b) : (static member MinValue: ^b) ()) let cast v = ((^a or ^b) : (static member op_Explicit: ^b -> ^a) v) value > cast minRange let inline test v = isWithinMinMaxRange<MyByte, _> vIt compile fine and runs fine when used.
That still leaves us with the two findings here:
- An unintelligible error (two of them, actually)
- Code that should compile but doesn't (and you may argue that the compiler issues a warning on
op_Explicitand that this is what can happen, the same problem happens withop_Implicit, which doesn't give the warning, but shows the same problems).
I see that this has been in the backlog for a while, and just want to bump it up if possible. I find that I run into it very easily when I try to do basic generic arithmetic, such as:
let inline plus< ^a, ^b, ^c when (^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)> (x : ^a) (y : ^b) = x + y // A type parameter is missing a constraint 'when ( ^a or ^?1493953) : (static member ( + ) : ^a * ^?1493953 -> ^?1493954)'Reacted by Abel BraaksmaTreating this as a duplicate of #385
Reopening this one, as the duplicate was resolved, but that resolution did not fix this issue. The original code still raises the weird numbered types in exceptions.
Reacted by Brian Berns

I must admit, I have seen this error before, but I have always managed to somehow mysteriously fix it, but now I'm stymied and I decided to report it.
The issue is: compile errors are raised on missing type parameters, but the error shows a garbled name which makes it virtually impossible to understand what is going on.
In addition, in this particular scenario, the error is incorrect, I think this source code should compile.
Repro steps
To repro, just copy the following code and try to compile, the error is on the last line.
Expected behavior
This should either compile just fine, or give an error that shows specifically what type parameter constraint is missing. The hashed names should not be shown. However, in this case, I don't think there's a constraint missing, as the call-site has equal type parameter constraints as the definition.
Actual behavior
It throws both FS0001 and FS0043, with equal texts:
Known workarounds
None, unfortunately (except for dynamic type resolution, but that is not an option here).
Related information