dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.08k stars 1.56k forks source link

[darthtml][Regression] Dart 2.13 and above throws `SpeechRecognitionResult.item is not a function or method` #47779

Open TahaTesser opened 2 years ago

TahaTesser commented 2 years ago

For complete details, see https://github.com/flutter/flutter/issues/86621

Description

When calling SpeechRecognitionResult.item in a SpeechRecognition Dart sample on Dart 2.12 using dart html, doesn't throw any errors.

However, something changed since 2.13, and the same example throws SpeechRecognitionResult.item is not a function or method.

Steps to reproduce just using dart example

Using the latest Dart version

  1. dart pub global activate webdev
  2. dart create -t web-simple quickstart

Paste in the code sample below in main.dart

minimal code dart sample ```dart import 'dart:html' as html; int _counter = 0; String _recognized = ''; html.SpeechRecognition? _webSpeech; void _incrementCounter() { _webSpeech?.stop(); _webSpeech?.onResult.listen((speechEvent) => _onResult(speechEvent)); _webSpeech?.interimResults = true; _webSpeech?.continuous = true; _webSpeech?.start(); _counter++; } void _onResult(html.SpeechRecognitionEvent event) { var results = event.results; if (null == results) return; for (html.SpeechRecognitionResult recognitionResult in results) { if (null == recognitionResult.length || recognitionResult.length == 0) { continue; } for (var altIndex = 0; altIndex < recognitionResult.length!; ++altIndex) { html.SpeechRecognitionAlternative alt = recognitionResult.item(altIndex); if (null != alt.transcript && null != alt.confidence) { _recognized = alt.transcript!; } } } } void main() { if (html.SpeechRecognition.supported) { _webSpeech = html.SpeechRecognition(); } _incrementCounter(); } ```
  1. webdev serve and open localhost address provided by the CLI into a browser on desktop
  2. Allow microphone permission and say Hello or any word into the microphone and checkout browser console

This line in https://raw.githubusercontent.com/dart-lang/sdk/main/sdk/lib/html/dart2js/html_dart2js.dart throws the error

class SpeechRecognitionResult extends Interceptor {
  // To suppress missing implicit constructor warnings.
  factory SpeechRecognitionResult._() {
    throw new UnsupportedError("Not supported");
  }

  bool? get isFinal native;

  int? get length native;

  SpeechRecognitionAlternative item(int index) native;
}

When checking js source, I noticed older Dart version used to have let alt = recognitionResult.item(altIndex);

But in later Dart SDK this is let alt = recognitionResult[$item](altIndex);

When using 2.12 Dart SDK, there is no issue https://github.com/dart-lang/sdk/releases/tag/2.12.0-285.0.dev

For a Flutter example see https://github.com/flutter/flutter/issues/86621#issue-947039277

This bug also affects a package https://github.com/csdcorp/speech_to_text/issues/242

TahaTesser commented 2 years ago

cc: @mraleph

mraleph commented 2 years ago

/cc @nshahan

nshahan commented 2 years ago

@srujzs Was there an update to the API here that you are aware of?

srujzs commented 2 years ago

Debugged this a bit with Nick and Mark, so relaying some thoughts here:

The generated call site has changed due to the use of sound null safety, specifically because native null assertions are added. Native null assertions change the call site to use the symbol lookup, so the stubbed method with the null assertion is called instead of the native method directly. In the normal workflow, this is fine and expected.

However, for some reason, the method isn't found, and I'm currently debugging to determine if it's because the type of SpeechRecognitionResult isn't registered, so the native type is never intercepted as a dart:html type. The SpeechRecognitionResult constructor isn't available in the top scope anymore (presumably a change in Chrome), so this adds credence to that theory, but the usual mechanisms of warning about this happening are not being triggered. I need to debug this a bit to find out how.

In the meantime, to unblock this bug, you can use dart:js_util as a workaround:

html.SpeechRecognitionAlternative alt = js_util.callMethod(recognitionResult, 'item', [altIndex]);