Skip to content

Conversation

@kerams
Copy link
Contributor

@kerams kerams commented Jun 15, 2023

Implements fsharp/fslang-suggestions#1262.

devenv_FWOQ9ny9h7

The parser changes could quite possibly be improved - it's not my forte.

RE: fsharp/fslang-suggestions#1262 (comment)

If we had intersection types there would be all sorts of restrictions - e.g. string & int is not possible nor any sealed type.

Elsewhere in the code, there's this check:

if newOk = NoNewTypars && isSealedTy g tyR then
    errorR(Error(FSComp.SR.tcInvalidConstraintTypeSealed(), m))

Not sure why this should only kick in for NoNewTypars. In TcIntersectionConstraint new typars seemed to always be OK, so such check would have no effect. However, currently we get this, which should be sufficient anyway:

image

@kerams kerams requested a review from a team as a code owner June 15, 2023 17:21
@vzarytovskii
Copy link
Member

Probably needs a small addition to rfc/new small rfc, so behaviour is documented.

@Lanayx
Copy link
Contributor

Lanayx commented Jun 15, 2023

@kerams will it make possible to intersect generic and non-generic restrictions? E.g.

let test (env: 'T & #IDisposable & #ILogger<'T>) =
    ()

@kerams
Copy link
Contributor Author

kerams commented Jun 15, 2023

Yes, but unless I am misunderstanding something, your constraints are not satisfiable. 'T cannot be an ILogger of itself.

This appears to be doable:

let test (env: 't & #seq<'u> & #Collections.IEnumerable) =
    ()

test [ [ 1 ] ]

@Lanayx
Copy link
Contributor

Lanayx commented Jun 15, 2023

'T cannot be an ILogger of itself.

I think it can, the whole Generic Maths feature is build atop of 'T when 'T :> INumber<'T>
https://learn.microsoft.com/en-us/dotnet/standard/generics/math

@kerams
Copy link
Contributor Author

kerams commented Jun 15, 2023

@Lanayx, you're right. I don't quite understand how, but this works:

let test (env: 't & #System.Numerics.INumber<'t> & #IEquatable<'t>) =
    ()

let test2 (env: 't when 't :> #System.Numerics.INumber<'t> and 't :> IEquatable<'t>) =
    ()

test 1
test2 1

@vzarytovskii
Copy link
Member

@Lanayx, you're right. I don't quite understand how, but this works:

let test (env: 't & #System.Numerics.INumber<'t> & #IEquatable<'t>) =
    ()

let test2 (env: 't when 't :> #System.Numerics.INumber<'t> and 't :> IEquatable<'t>) =
    ()

test 1
test2 1

Yeah, that's pretty much due to changes we introduced for static abstracts in interfaces. At least I believe so.

@Lanayx
Copy link
Contributor

Lanayx commented Jun 15, 2023

That's great! In that case it will subsume the old syntax (which I didn't like anyway), e.g. instead of

let test (env: 'T when INumber<'T>) =
    ()

we'll be able to write

let test (env: 'T & #INumber<'T>) =
    ()

@En3Tho
Copy link
Contributor

En3Tho commented Jun 15, 2023

Why do you think constraints are not solvable? It's just an interface like for example INumber'TSelf which works via implementing an interface of itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

7 participants