dotnet / dotnet/fsharp

Units of measure can affect compiled form of integral ranges

Open
#17,046 2 comments 0 reactions 0 assignees View on GitHub
Area-Compiler-Optimization Feature Improvement
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 22h
Merged PRs (30d)
144

Description

When looking into #17025, I found that the presence of units of measure can affect the compiled form of the range `(..)` and range-step `(.. ..)` operators. This applies to their use in bare `for`-loops as well as in computed collections.

When `start` and `finish` (for `(..)`) and `start`, `step`, and `finish` (for `(.. ..)`) are all literal values, local variables, or parameter values, the compiled form with units of measure is the same as it is without units of measure.

But when any of `start`, `step`, or `finish` is a function call, method call, property access, etc., the compiled form with units of measure diverges from the compiled form without units of measure.

That is, these pairs are [compiled identically](https://sharplab.io/#v2:DYLgZgzgPg9gDgUwHYAIDKBPCAXBBbAWACh5kUAxNACwEMAnOAOgBEbsbGBVJAS20xz4IjNAEkuvfhjwAjGMAjFiYGHRSoeqAIyNGOvQAYUAExgoeAcySqEKABRhgMNupQAqNykfPs6gJTKqq6aKFoAPHgAfLrhUTEGEZEmZpbWdLYOTi6oHl5ZvkgBRMTACL4AHhAoALwoANpQsdF6ifGJUAC6JWUoWDX1jTHxnUpEpRUQAOT9DfpzBiNjPVjTtbOtLXGG7R1AA) (as expected):

```fsharp
for n in 1..1..10 do ignore (float n ** float n)
for n in 1..1..10 do ignore (float n ** float n)
```

```fsharp
[1..1..10]
[1..1..10]
```

```fsharp
[|1..1..10|]
[|1..1..10|]
```

But these pairs are [compiled differently](https://sharplab.io/#v2:DYLgZgzgPg9gDgUwHYAIDKBPCAXBBbAWACh5kUAxNACwEMAnOAOgBEbsbGBVJAS20xz4IjNAEkuvfhjwAjGMAjFiwBNhRgAjCgDmKALzqYdFKh6pdACgCUjRhtsaADCgAmMFD21IjCFBbDAMGwmKABUoeqBwUhWyqrqAEw6+obGpuZ+NnYAPHgAfA6OuXmu7p7edL7+UWqo4ZFBtbFEcWpgAMzJBgDalln2do4Auq3qACxdKL2ZDsWFxSMtRCptAKyT3VB9DoVQiyvqAGwbWzM5+fP5e0A==):

```fsharp
let f1 g = for n in g ()..1..10 do ignore (float n ** float n)
let f2 g = for n in g ()..1..10 do ignore (float n ** float n)
```

```fsharp
let f3 g = [g ()..1..10]
let f4 g = [g ()..1..10]
```

```fsharp
let f5 g = [|g ()..1..10|]
let f6 g = [|g ()..1..10|]
```

This divergence is happening in the compiler somewhere before `for`-loops or computed collections are optimized, which means that neither the longstanding optimization for integer `for`-loops over ranges with a step of `1` or `-1` nor the new optimizations introduced in #16650 are applied in certain scenarios when units of measure are involved.

I don't believe that this should be the case. Ideally, the presence of units of measure should not affect the compiled form of these constructs.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.