dart-lang / dart-lang/language
Type inference defaulting to dynamic can cause hard to find issues
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
This is my first post here, apologies if I'm not correctly following protocol. I've run into an issue that is caused by Dart's silent defaulting to `dynamic` if type inference doesn't find a concrete type. Consider the following code:
```dart
Type typeOf() => T;
class Value extends InheritedWidget {
final T value;
Value({this.value, Widget child}) : super(child: child);
@override bool updateShouldNotify(_) => true;
static T of(BuildContext context) {
final type = typeOf>();
final provider = context.inheritFromWidgetOfExactType(type) as Value;
return provider.value; // <-- (1)
}
}
class StatefulValue extends StatefulWidget {
final T Function(BuildContext) valueBuilder;
final Widget child;
StatefulValue({this.valueBuilder, this.child}) : super();
@override createState() => _StatefulValueState(); // <-- (2)
}
class _StatefulValueState extends State> {
T _value;
@override initState() {
super.initState();
_value = widget.valueBuilder(context);
}
@override build(context) => Value(value: _value, child: widget.child);
}
```
This is then used like so:
```dart
class HomePage extends StatelessWidget {
@override build(context) => StatefulValue(
valueBuilder: (_) => 'Hello!',
child: Builder(
builder: (context) => Scaffold(
appBar: AppBar(
title: Text(Value.of(context)),
),
),
),
);
}
```
The details of the example don't matter, it just aims to demonstrate a subtle bug that's hidden within typical "Flutter noise": The code compiles without warnings, but instead of showing the expected 'Hello!' Text in the app bar, a runtime error is thrown: `"The getter 'value' was called on null."` (see `(1)`).
It took me quite a while to find the fix (see `(2)`):
```dart
@override createState() => _StatefulValueState();
```
In hindsight it makes perfect sense: without the `` annotation, Dart defaults to `_StatefulValueState`. An easily made mistake that creates a cascade of issues that's very hard to backtrack. In fact, now that I'm aware of this, I'm not at all sure I haven't made similar mistakes elsewhere that just haven't surfaced as bugs yet.
Testing surely helps, but I wonder if the Dart languge itself could be more helpful in such cases: If the analyzer fails to infer a concrete type, that's probably because I did something wrong unintentionally, and I surely would benefit from knowing about it. I wonder, would a compiler warning (or even a compile-time error) be feasible?
Contributor guide
Assessment
This issue has not been assessed yet.