dart-lang / dart-lang/language
Issue with type inference in constant factory constructors
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
Hi,
I found a possible issue while working with constant factory constructors (i.e. `const factory`) [^1].
[fpdart](https://pub.dev/packages/fpdart) defines a constant [factory constructor for the Option type](https://github.com/SandroMaglione/fpdart/blob/e892c8d158cc63c4e6d5b4eebaa95107c708d66a/lib/src/option.dart#L474) as follows:
```dart
/// Return a [None].
const factory Option.none() = None;
/// Return a `Some(a)`.
const factory Option.of(T t) = Some;
```
We found an issue when the type system tries to infer the generic type in some functions, for example [`map`](https://github.com/SandroMaglione/fpdart/blob/e892c8d158cc63c4e6d5b4eebaa95107c708d66a/lib/src/option.dart#L664):
```dart
Option map(B Function(T t) f) => const Option.none();
```
Returning a `const` using the factory constructor `none()` infers the type as `Option`. If instead the return is not marked as `const` the return type is `Option` as expected:


This causes **runtime** issues when working with the result of `map`. For example:
```dart
import 'package:fpdart/fpdart.dart';
Option nonEmptyString(String? s) => Option.fromNullable(s).map(
(t) => t.trim(),
);
void main() {
nonEmptyString(null).alt(() => nonEmptyString('hi'));
}
```
VSCode infers the return type as `Option`:

but then when you run the app it fails with the following error:
```shell
Unhandled exception:
type '() => Option' is not a subtype of type '() => Option' of 'orElse'
#0 None.alt (package:fpdart/src/option.dart)
#1 main (file:///Users/sandromaglione/Development/projects/dart/fpdart/example/src/either/cast.dart:13:24)
cast.dart:13
#2 _delayEntrypointInvocation. (dart:isolate-patch/isolate_patch.dart:297:19)
#3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
```
This happens because `map` in the function `nonEmptyString` returns `Option`, that fails when using [`alt`](https://github.com/SandroMaglione/fpdart/blob/e892c8d158cc63c4e6d5b4eebaa95107c708d66a/lib/src/option.dart#L676) (which calls `orElse` as reported in the error) with a type error.
Is this behaviour expected using `const factory`? Could there be an issue with inference?
[^1]: [PR](https://github.com/SandroMaglione/fpdart/pull/92)
Contributor guide
Research direction
Start with the constant factory constructor examples in the issue and compare the inferred types of the const and non-const returns in Option.map. Then trace how the result is used by Option.alt and its reported orElse failure. Done means determining whether this inference is expected and documenting or resolving the language behavior with a corresponding reproduction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100