Open gmpassos opened 6 days ago
Summary: The issue is that dart2js
fails to compile a lambda function used with the map
method on a list of SpeechSynthesisVoice
objects, resulting in a type error. The code compiles and runs correctly in DDC
, but fails in dart2js
webdev release mode.
If you need to investigate the generated JS code, force dart2js
to not optimize and minify
it:
build.yaml
:
targets:
$default:
builders:
build_web_compilers:entrypoint:
options:
dart2js_args:
- -O1
- --no-minify
- --disable-program-split
- --no-source-maps
The inferred static type of the closure is indeed (SpeechSynthesisVoice) => String?
. This is expected, since voices
has static type List<SpeechSynthesisVoice>?
. However, at runtime, print(voices.runtimeType)
shows that it's actually JSArray<dynamic>
, so .map
expects a closure whose parameter type is dynamic
, hence the failure.
This is because the array ultimately comes directly from window.speechSynthesis.getVoices()
in JS, which doesn't tag the result with the element type.
/cc @srujzs @rakudrama
I guess the real issue then is that List<SpeechSynthesisVoice>
is not sound here with respect to the generic type, but that's a known issue in how we intercept JSArray
. The workaround then would just be to use a lambda that accepts dynamic
, but that seems ugly.
Consider using package:web
instead where you'll get better static typing: https://github.com/dart-lang/web/blob/8478cd27d574249eca3d41f9135458dfda2762c8/web/lib/src/dom/speech_api.dart#L319.
I guess the real issue then is that
List<SpeechSynthesisVoice>
is not sound here with respect to the generic type, but that's a known issue in how we interceptJSArray
. The workaround then would just be to use a lambda that acceptsdynamic
, but that seems ugly.Consider using
package:web
instead where you'll get better static typing: https://github.com/dart-lang/web/blob/8478cd27d574249eca3d41f9135458dfda2762c8/web/lib/src/dom/speech_api.dart#L319.
For me this is a bug on dart2js
, specially because DDC works. This shouldn't be treated as a specific bug on dart:html
.
For me this is a bug on dart2js, specially because DDC works. This shouldn't be treated as a specific bug on dart:html.
I agree (although DDC working doesn't necessarily indicate that), but this is a problem that materializes specifically for dart:html
and older interop versions. There are a few possible solutions e.g. adding the generic type manually, but I'm not sure what all the corner cases there are yet. We can keep this open, but it is preferable to use package:web
to avoid these issues that may take much longer to resolve e.g.
import 'package:web/web.dart' as web;
void main() {
web.window.speechSynthesis.getVoices().toDart.map((e) => e.lang).toList();
}
@srujzs I'm currently avoiding the bug with this:
import 'dart:html';
...
var voicesLang = voices
.map((Object? e) => e is SpeechSynthesisVoice ? e.lang : null)
.nonNulls
.toSet();
I've encountered an unusual issue with
dart2js
and have isolated a code snippet that reproduces the bug:DDC
anddart2js
.DDC
.dart2js
(in webdev release mode).Note that the list
voices
needs to be populated to reproduce the bug.I'm not sure of the exact issue, but it seems that the compiled JS is expecting a different type for the map lambda parameter.
Run it:
Open in the browser:
http://127.0.0.1:8080
Browser Console output:
$>
dart info
pubspec.lock
: