Version 2.14.0-241.0.dev
Merge commit '3405b943389fa0d56fd335361ac3fa861057c52e' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 44baa91..efcb595 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -82,7 +82,7 @@
"name": "analyzer",
"rootUri": "../pkg/analyzer",
"packageUri": "lib/",
- "languageVersion": "2.13"
+ "languageVersion": "2.12"
},
{
"name": "analyzer_cli",
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 9595fbe..52d52dc 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -567,6 +567,7 @@
HintCode.MUST_CALL_SUPER,
HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR,
HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW,
+ HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
HintCode.NULL_AWARE_BEFORE_OPERATOR,
HintCode.NULL_AWARE_IN_CONDITION,
HintCode.NULL_AWARE_IN_LOGICAL_OPERATOR,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 66cfda4..cedb70b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -869,6 +869,7 @@
var result = await getResolvedLibrary2(path);
if (result is NotPathOfUriResult) {
+ // ignore: null_argument_to_non_null_type
return Future.value(); // bug?
}
@@ -1138,7 +1139,7 @@
Future<String> getUnitElementSignature(String path) {
_throwIfNotAbsolutePath(path);
if (!_fsState.hasUri(path)) {
- return Future.value();
+ return Future.value(); // ignore: null_argument_to_non_null_type
}
var completer = Completer<String>();
_unitElementSignatureFiles
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 14038d6..878e7c7 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -1683,6 +1683,16 @@
);
/**
+ * Users should not use `Future.value` or `Completer.complete` with a null
+ * argument if the type argument is non-nullable.
+ */
+ static const HintCode NULL_ARGUMENT_TO_NON_NULL_TYPE = HintCode(
+ 'NULL_ARGUMENT_TO_NON_NULL_TYPE',
+ "'{0}' should not be called with a null argument for the non-nullable "
+ "type argument '{1}'",
+ correction: 'Try adding a non-null argument.');
+
+ /**
* When the left operand of a binary expression uses '?.' operator, it can be
* `null`.
*/
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 0dcc2f6..a1d8739 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -27,6 +27,7 @@
import 'package:analyzer/src/error/deprecated_member_use_verifier.dart';
import 'package:analyzer/src/error/error_handler_verifier.dart';
import 'package:analyzer/src/error/must_call_super_verifier.dart';
+import 'package:analyzer/src/error/null_safe_api_verifier.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -76,6 +77,8 @@
final ErrorHandlerVerifier _errorHandlerVerifier;
+ final NullSafeApiVerifier _nullSafeApiVerifier;
+
/// The [WorkspacePackage] in which [_currentLibrary] is declared.
final WorkspacePackage? _workspacePackage;
@@ -115,6 +118,7 @@
_mustCallSuperVerifier = MustCallSuperVerifier(_errorReporter),
_errorHandlerVerifier =
ErrorHandlerVerifier(_errorReporter, typeProvider, typeSystem),
+ _nullSafeApiVerifier = NullSafeApiVerifier(_errorReporter, typeSystem),
_workspacePackage = workspacePackage {
_deprecatedVerifier.pushInDeprecatedValue(_currentLibrary.hasDeprecated);
_inDoNotStoreMember = _currentLibrary.hasDoNotStore;
@@ -567,6 +571,7 @@
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
_deprecatedVerifier.instanceCreationExpression(node);
+ _nullSafeApiVerifier.instanceCreation(node);
_checkForLiteralConstructorUse(node);
super.visitInstanceCreationExpression(node);
}
@@ -644,6 +649,7 @@
_deprecatedVerifier.methodInvocation(node);
_checkForNullAwareHints(node, node.operator);
_errorHandlerVerifier.verifyMethodInvocation(node);
+ _nullSafeApiVerifier.methodInvocation(node);
super.visitMethodInvocation(node);
}
diff --git a/pkg/analyzer/lib/src/error/null_safe_api_verifier.dart b/pkg/analyzer/lib/src/error/null_safe_api_verifier.dart
new file mode 100644
index 0000000..a0308f1
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/null_safe_api_verifier.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/error/hint_codes.dart';
+
+/// Verifies usages of `Future.value` and `Completer.complete` when null-safety
+/// is enabled.
+///
+/// `Future.value` and `Completer.complete` both accept a `FutureOr<T>?` as an
+/// optional argument but throw an exception when `T` is non-nullable and `null`
+/// is passed as an argument.
+///
+/// This verifier detects and reports those scenarios.
+class NullSafeApiVerifier {
+ final ErrorReporter _errorReporter;
+ final TypeSystemImpl _typeSystem;
+
+ NullSafeApiVerifier(this._errorReporter, this._typeSystem);
+
+ /// Reports an error if the expression creates a `Future<T>.value` with a non-
+ /// nullable value `T` and an argument that is effectively `null`.
+ void instanceCreation(InstanceCreationExpression expression) {
+ if (!_typeSystem.isNonNullableByDefault) return;
+
+ final constructor = expression.constructorName.staticElement;
+ if (constructor == null) return;
+
+ final type = constructor.returnType;
+ final isFutureValue = type.isDartAsyncFuture && constructor.name == 'value';
+
+ if (isFutureValue) {
+ _checkTypes(expression, 'Future.value', type.typeArguments.single,
+ expression.argumentList);
+ }
+ }
+
+ /// Reports an error if `Completer<T>.complete` is invoked with a non-nullable
+ /// `T` and an argument that is effectively `null`.
+ void methodInvocation(MethodInvocation node) {
+ if (!_typeSystem.isNonNullableByDefault) return;
+
+ final targetType = node.realTarget?.staticType;
+ final targetClass = targetType?.element;
+ if (targetClass == null || targetType is! InterfaceType) return;
+
+ if (targetClass.library?.isDartAsync == true &&
+ targetClass.name == 'Completer' &&
+ node.methodName.name == 'complete') {
+ _checkTypes(node, 'Completer.complete', targetType.typeArguments.single,
+ node.argumentList);
+ }
+ }
+
+ void _checkTypes(
+ Expression node, String memberName, DartType type, ArgumentList args) {
+ // If there's more than one argument, something else is wrong (and will
+ // generate another diagnostic). Also, only check the argument type if we
+ // expect a non-nullable type in the first place.
+ if (args.arguments.length > 1 || !_typeSystem.isNonNullable(type)) return;
+
+ final argument = args.arguments.isEmpty ? null : args.arguments.single;
+ final argumentType = argument?.staticType;
+ // Skip if the type is not currently resolved.
+ if (argument != null && argumentType == null) return;
+
+ final argumentIsNull =
+ argument == null || _typeSystem.isNull(argumentType!);
+
+ if (argumentIsNull) {
+ _errorReporter.reportErrorForNode(
+ HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
+ argument ?? node,
+ [memberName, type.getDisplayString(withNullability: true)]);
+ }
+ }
+}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 529d76a..b3cbff8 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -4,7 +4,7 @@
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
environment:
- sdk: '>=2.13.0 <3.0.0'
+ sdk: '>=2.12.0 <3.0.0'
dependencies:
_fe_analyzer_shared: ^22.0.0
diff --git a/pkg/analyzer/test/src/diagnostics/null_argument_to_non_null_type_test.dart b/pkg/analyzer/test/src/diagnostics/null_argument_to_non_null_type_test.dart
new file mode 100644
index 0000000..5e9409d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/null_argument_to_non_null_type_test.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/error/hint_codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(NullArgumentToNonNullCompleterCompleteTest);
+ defineReflectiveTests(NullArgumentToNonNullFutureValueTest);
+ });
+}
+
+@reflectiveTest
+class NullArgumentToNonNullCompleterCompleteTest
+ extends PubPackageResolutionTest {
+ test_absent() async {
+ await assertErrorsInCode('''
+import 'dart:async';
+void f() => Completer<int>().complete();
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 33, 27),
+ ]);
+ }
+
+ test_dynamic() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+void f() {
+ Completer<int>().complete(null as dynamic);
+}
+''');
+ }
+
+ test_legacy() async {
+ await assertNoErrorsInCode('''
+// @dart=2.9
+import 'dart:async';
+
+void f() {
+ final c = Completer<int>();
+ c.complete();
+ c.complete(null);
+}
+''');
+ }
+
+ test_null() async {
+ await assertErrorsInCode('''
+import 'dart:async';
+void f() => Completer<int>().complete(null);
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 59, 4),
+ ]);
+ }
+
+ test_nullable() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+void f() {
+ final c = Completer<int?>();
+ c.complete();
+ c.complete(null);
+}
+''');
+ }
+
+ test_nullType() async {
+ await assertErrorsInCode('''
+import 'dart:async';
+void f(Null a) => Completer<int>().complete(a);
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 65, 1),
+ ]);
+ }
+}
+
+@reflectiveTest
+class NullArgumentToNonNullFutureValueTest extends PubPackageResolutionTest {
+ test_absent() async {
+ await assertErrorsInCode('''
+void foo() => Future<int>.value();
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 14, 19),
+ ]);
+ }
+
+ test_dynamic() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+void f() {
+ Future<int>.value(null as dynamic);
+}
+''');
+ }
+
+ test_legacy() async {
+ await assertNoErrorsInCode('''
+// @dart=2.9
+void f() {
+ Future<int>.value();
+ Future<int>.value(null);
+}
+''');
+ }
+
+ test_null() async {
+ await assertErrorsInCode('''
+void foo() => Future<int>.value(null);
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 32, 4),
+ ]);
+ }
+
+ test_nullable() async {
+ await assertNoErrorsInCode('''
+void f() {
+ Future<int?>.value();
+ Future<int?>.value(null);
+}
+''');
+ }
+
+ test_nullType() async {
+ await assertErrorsInCode('''
+void foo(Null a) => Future<int>.value(a);
+''', [
+ error(HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE, 38, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 188a40a..8af03ed 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -501,6 +501,8 @@
import 'not_iterable_spread_test.dart' as not_iterable_spread;
import 'not_map_spread_test.dart' as not_map_spread;
import 'not_null_aware_null_spread_test.dart' as not_null_aware_null_spread;
+import 'null_argument_to_non_null_type_test.dart'
+ as null_argument_to_non_null_type;
import 'null_aware_before_operator_test.dart' as null_aware_before_operator;
import 'null_aware_in_condition_test.dart' as null_aware_in_condition;
import 'null_aware_in_logical_operator_test.dart'
@@ -1039,6 +1041,7 @@
not_iterable_spread.main();
not_map_spread.main();
not_null_aware_null_spread.main();
+ null_argument_to_non_null_type.main();
null_aware_before_operator.main();
null_aware_in_condition.main();
null_aware_in_logical_operator.main();
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index a57232b..adbf857 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -335,6 +335,8 @@
FunctionEntity findHelperFunction(String name);
ClassEntity get closureClass;
+ ClassEntity get closureClass0Args;
+ ClassEntity get closureClass2Args;
ClassEntity get boundClosureClass;
@@ -516,8 +518,6 @@
InterfaceType get externalNameType;
- ConstructorEntity get symbolValidatedConstructor;
-
// From dart:_js_embedded_names
/// Holds the class for the [JsGetName] enum.
@@ -569,8 +569,6 @@
bool isCreateInvocationMirrorHelper(MemberEntity member);
- bool isSymbolValidatedConstructor(ConstructorEntity element);
-
ClassEntity get metaNoInlineClass;
ClassEntity get metaTryInlineClass;
@@ -1536,6 +1534,16 @@
@override
ClassEntity get closureClass => _closureClass ??= _findHelperClass('Closure');
+ ClassEntity _closureClass0Args;
+ @override
+ ClassEntity get closureClass0Args =>
+ _closureClass0Args ??= _findHelperClass('Closure0Args');
+
+ ClassEntity _closureClass2Args;
+ @override
+ ClassEntity get closureClass2Args =>
+ _closureClass2Args ??= _findHelperClass('Closure2Args');
+
ClassEntity _boundClosureClass;
@override
ClassEntity get boundClosureClass =>
@@ -2061,11 +2069,6 @@
@override
InterfaceType get externalNameType => _getRawType(externalNameClass);
- @override
- ConstructorEntity get symbolValidatedConstructor =>
- _symbolValidatedConstructor ??=
- _findConstructor(symbolImplementationClass, 'validated');
-
/// Returns the field that holds the internal name in the implementation class
/// for `Symbol`.
FieldEntity _symbolImplementationField;
@@ -2073,15 +2076,6 @@
_env.lookupLocalClassMember(symbolImplementationClass, '_name',
required: true);
- ConstructorEntity _symbolValidatedConstructor;
- @override
- bool isSymbolValidatedConstructor(ConstructorEntity element) {
- if (_symbolValidatedConstructor != null) {
- return element == _symbolValidatedConstructor;
- }
- return false;
- }
-
// From dart:_native_typed_data
ClassEntity _typedArrayOfIntClass;
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index f136327..b0f12cf 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -291,6 +291,12 @@
static const ParameterStructure zeroArguments =
ParameterStructure._(0, 0, [], {}, 0);
+ static const ParameterStructure oneArgument =
+ ParameterStructure._(1, 1, [], {}, 0);
+
+ static const ParameterStructure twoArguments =
+ ParameterStructure._(2, 2, [], {}, 0);
+
static const List<ParameterStructure> _simple = [
ParameterStructure._(0, 0, [], {}, 0),
ParameterStructure._(1, 1, [], {}, 0),
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index cb72411..d50ddc1b 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -299,13 +299,6 @@
constantMapLiteral
]);
- BackendImpact _symbolConstructor;
-
- BackendImpact get symbolConstructor {
- return _symbolConstructor ??= new BackendImpact(
- staticUses: [_commonElements.symbolValidatedConstructor]);
- }
-
BackendImpact _constSymbol;
BackendImpact get constSymbol {
@@ -574,8 +567,11 @@
BackendImpact _functionClass;
BackendImpact get functionClass {
- return _functionClass ??=
- new BackendImpact(globalClasses: [_commonElements.closureClass]);
+ return _functionClass ??= new BackendImpact(globalClasses: [
+ _commonElements.closureClass,
+ _commonElements.closureClass0Args,
+ _commonElements.closureClass2Args,
+ ]);
}
BackendImpact _mapClass;
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index ad3877c..6b3e73c 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -164,8 +164,7 @@
bool _isValidEntity(Entity element) {
if (element is ConstructorEntity &&
(element == _commonElements.streamIteratorConstructor ||
- _commonElements.isSymbolConstructor(element) ||
- _commonElements.isSymbolValidatedConstructor(element))) {
+ _commonElements.isSymbolConstructor(element))) {
// TODO(johnniwinther): These are valid but we could be more precise.
return true;
} else if (element == _commonElements.symbolImplementationClass ||
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 9596fd0..c57ab1c 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -114,9 +114,6 @@
case Feature.SUPER_NO_SUCH_METHOD:
registerImpact(_impacts.superNoSuchMethod);
break;
- case Feature.SYMBOL_CONSTRUCTOR:
- registerImpact(_impacts.symbolConstructor);
- break;
case Feature.SYNC_FOR_IN:
registerImpact(_impacts.syncForIn);
break;
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index fd4296e..156ccb1 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -241,7 +241,14 @@
final bool onlyForConstructor;
final bool isDirectlyInstantiated;
final bool isNative;
- final bool isClosureBaseClass; // Common base class for closures.
+
+ /// `true` if this is the one class that is the root of all 'Closure' classes.
+ final bool isClosureBaseClass;
+
+ /// If non-null, this class is used as a base class for closures with a fixed
+ /// small number of arguments in order to inherit `Function.apply`
+ /// metadata. The value is the fixed number of arguments.
+ final int sharedClosureApplyMetadata;
final bool isMixinApplicationWithMembers;
@@ -279,6 +286,7 @@
this.isDirectlyInstantiated,
this.isNative,
this.isClosureBaseClass,
+ this.sharedClosureApplyMetadata,
this.isMixinApplicationWithMembers}) {
assert(onlyForRti != null);
assert(onlyForConstructor != null);
@@ -492,6 +500,8 @@
/// functions that can be torn off.
final bool isClosureCallMethod;
+ final bool inheritsApplyMetadata;
+
/// True if the interceptor calling convention is used for this method.
final bool isIntercepted;
@@ -512,6 +522,7 @@
int requiredParameterCount,
/* List | Map */ optionalParameterDefaultValues,
this.isClosureCallMethod,
+ this.inheritsApplyMetadata,
this.isIntercepted,
js.Expression functionType,
int applyIndex,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 6c581a5..2a8ae0a 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -557,7 +557,18 @@
bool onlyForRti = _nativeData.isJsInteropClass(cls);
bool hasRtiField = _rtiNeed.classNeedsTypeArguments(cls);
bool onlyForConstructorOrRti = onlyForConstructor || onlyForRti;
+
+ // Recognize the specialized base classes for closures.
bool isClosureBaseClass = cls == _commonElements.closureClass;
+ int sharedClosureApplyMetadata;
+ if (cls == _commonElements.closureClass) {
+ // The root base class has metadata for single-argument closures.
+ sharedClosureApplyMetadata = 1;
+ } else if (cls == _commonElements.closureClass0Args) {
+ sharedClosureApplyMetadata = 0;
+ } else if (cls == _commonElements.closureClass2Args) {
+ sharedClosureApplyMetadata = 2;
+ }
List<Method> methods = [];
List<StubMethod> callStubs = [];
@@ -712,6 +723,7 @@
assert(!_nativeData.isNativeClass(cls));
assert(methods.isEmpty);
assert(!isClosureBaseClass);
+ assert(sharedClosureApplyMetadata == null);
result = MixinApplication(cls, typeData, name, instanceFields, callStubs,
checkedSetters, gettersSetters, isChecks, typeTests.functionTypeIndex,
@@ -738,6 +750,7 @@
onlyForConstructor: onlyForConstructor,
isNative: _nativeData.isNativeClass(cls),
isClosureBaseClass: isClosureBaseClass,
+ sharedClosureApplyMetadata: sharedClosureApplyMetadata,
isMixinApplicationWithMembers: isMixinApplicationWithMembers);
}
_classes[cls] = result;
@@ -814,6 +827,7 @@
bool tearOffNeedsDirectAccess = false;
js.Name tearOffName;
bool isClosureCallMethod = false;
+ bool inheritsApplyMetadata = false;
bool isNotApplyTarget =
!element.isFunction || element.isGetter || element.isSetter;
@@ -829,6 +843,17 @@
if (element.enclosingClass.isClosure) {
canTearOff = false;
isClosureCallMethod = true;
+ ClassEntity superclass =
+ _elementEnvironment.getSuperClass(element.enclosingClass);
+ if (superclass == _commonElements.closureClass &&
+ element.parameterStructure == ParameterStructure.oneArgument ||
+ superclass == _commonElements.closureClass0Args &&
+ element.parameterStructure ==
+ ParameterStructure.zeroArguments ||
+ superclass == _commonElements.closureClass2Args &&
+ element.parameterStructure == ParameterStructure.twoArguments) {
+ inheritsApplyMetadata = true;
+ }
} else {
// Careful with operators.
bool needsSuperGetter = _codegenWorld.methodsNeedsSuperGetter(element);
@@ -881,6 +906,7 @@
tearOffName: tearOffName,
tearOffNeedsDirectAccess: tearOffNeedsDirectAccess,
isClosureCallMethod: isClosureCallMethod,
+ inheritsApplyMetadata: inheritsApplyMetadata,
isIntercepted: isIntercepted,
aliasName: aliasName,
canBeApplied: canBeApplied,
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 9f40195..bf57340 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -592,6 +592,9 @@
_call1Name ??= _namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX1);
js.Name get call2Name =>
_call2Name ??= _namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX2);
+ List<js.Name> _callNamesByArity;
+ List<js.Name> get callNamesByArity =>
+ _callNamesByArity ??= [call0Name, call1Name, call2Name];
FragmentEmitter(
this._options,
@@ -1068,26 +1071,31 @@
allMethods.forEach((Method method) {
emitInstanceMethod(method)
.forEach((js.Expression name, js.Expression code) {
- var prop = js.Property(name, code);
- registerEntityAst(method.element, prop);
- properties.add(prop);
+ final property = js.Property(name, code);
+ registerEntityAst(method.element, property);
+ properties.add(property);
});
});
- if (cls.isClosureBaseClass) {
- // Closures extend a common base class, so we can put properties on the
- // prototype for common values.
+ // Closures have metadata that is often the same. We avoid repeated metadata
+ // by putting it on a shared superclass. It is overridden in the subclass if
+ // necessary.
- // Closures taking exactly one argument are common.
+ int arity = cls.sharedClosureApplyMetadata;
+ if (arity != null) {
+ // This is a closure base class that has the specialized `Function.apply`
+ // metadata for functions taking exactly [arity] arguments.
properties.add(js.Property(js.string(_namer.fixedNames.callCatchAllName),
- js.quoteName(call1Name)));
+ js.quoteName(callNamesByArity[arity])));
properties.add(js.Property(
- js.string(_namer.fixedNames.requiredParameterField), js.number(1)));
+ js.string(_namer.fixedNames.requiredParameterField),
+ js.number(arity)));
+ }
+ if (cls.isClosureBaseClass) {
// Most closures have no optional arguments.
properties.add(js.Property(
- js.string(_namer.fixedNames.defaultValuesField),
- new js.LiteralNull()));
+ js.string(_namer.fixedNames.defaultValuesField), js.LiteralNull()));
}
return new js.ObjectInitializer(properties);
@@ -1112,35 +1120,27 @@
}
if (method.isClosureCallMethod && method.canBeApplied) {
- // TODO(sra): We should also add these properties for the user-defined
- // `call` method on classes. Function.apply is currently broken for
- // complex cases. [forceAdd] might be true when this is fixed.
- bool forceAdd = !method.isClosureCallMethod;
+ // The `call` method might flow to `Function.apply`, so the metadata for
+ // `Function.apply` is needed.
- // Common case of "call*": "call$1" is stored on the Closure class.
- if (method.applyIndex != 0 ||
- method.parameterStubs.isNotEmpty ||
- method.requiredParameterCount != 1 ||
- forceAdd) {
+ // Avoid adding the metadata if a superclass has the same metadata.
+ if (!method.inheritsApplyMetadata) {
js.Name applyName = method.applyIndex == 0
? method.name
: method.parameterStubs[method.applyIndex - 1].name;
properties[js.string(_namer.fixedNames.callCatchAllName)] =
js.quoteName(applyName);
- }
- // Common case of '1' is stored on the Closure class.
- if (method.requiredParameterCount != 1 || forceAdd) {
properties[js.string(_namer.fixedNames.requiredParameterField)] =
js.number(method.requiredParameterCount);
- }
- js.Expression defaultValues =
- _encodeOptionalParameterDefaultValues(method);
- // Default values property of `null` is stored on the common JS
- // superclass.
- if (defaultValues is! js.LiteralNull || forceAdd) {
- properties[js.string(_namer.fixedNames.defaultValuesField)] =
- defaultValues;
+ js.Expression defaultValues =
+ _encodeOptionalParameterDefaultValues(method);
+ // Default values property of `null` is stored on the common JS
+ // superclass.
+ if (defaultValues is! js.LiteralNull) {
+ properties[js.string(_namer.fixedNames.defaultValuesField)] =
+ defaultValues;
+ }
}
}
}
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index c07ccea..8a4928d 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -417,7 +417,8 @@
Map<ir.VariableDeclaration, JRecordField> boxedVariables,
KernelScopeInfo info,
{bool createSignatureMethod}) {
- ClassEntity superclass = _commonElements.closureClass;
+ ClassEntity superclass =
+ _chooseClosureSuperclass(originalClosureFunctionNode);
JsClosureClassInfo closureClassInfo = _elementMap.constructClosureClass(
member,
@@ -440,6 +441,21 @@
return closureClassInfo;
}
+ ClassEntity _chooseClosureSuperclass(ir.FunctionNode node) {
+ // Choose a superclass so that similar closures can share the metadata used
+ // by `Function.apply`.
+ int requiredParameterCount = node.requiredParameterCount;
+ if (node.typeParameters.isEmpty &&
+ node.namedParameters.isEmpty &&
+ requiredParameterCount == node.positionalParameters.length) {
+ if (requiredParameterCount == 0) return _commonElements.closureClass0Args;
+ if (requiredParameterCount == 2) return _commonElements.closureClass2Args;
+ }
+ // Note that the base closure class has specialized metadata for the common
+ // case of single-argument functions.
+ return _commonElements.closureClass;
+ }
+
OutputUnitData _convertOutputUnitData(JsToFrontendMapImpl map,
OutputUnitData data, ClosureData closureDataLookup) {
// Convert front-end maps containing K-class and K-local function keys to a
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index bd6095b..508b578 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -340,10 +340,6 @@
impactBuilder.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
}
- if (commonElements.isSymbolConstructor(constructor)) {
- impactBuilder.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
- }
-
if (target.isExternal &&
constructor.isFromEnvironmentConstructor &&
!isConst) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 56c3746..ad8f434 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -5546,9 +5546,6 @@
node.arguments,
typeArguments,
sourceInformation));
- if (_commonElements.isSymbolConstructor(constructor)) {
- constructor = _commonElements.symbolValidatedConstructor;
- }
// TODO(johnniwinther): Remove this when type arguments are passed to
// constructors like calling a generic method.
_addTypeArguments(arguments, _getClassTypeArguments(cls, node.arguments),
diff --git a/pkg/compiler/lib/src/universe/feature.dart b/pkg/compiler/lib/src/universe/feature.dart
index f907c36..8d8d9ba 100644
--- a/pkg/compiler/lib/src/universe/feature.dart
+++ b/pkg/compiler/lib/src/universe/feature.dart
@@ -62,9 +62,6 @@
/// super method.
SUPER_NO_SUCH_METHOD,
- /// A redirection to the `Symbol` constructor.
- SYMBOL_CONSTRUCTOR,
-
/// An synchronous for in statement, like `for (var e in i) {}`.
SYNC_FOR_IN,
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 317a63f..2addb57 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -4092,10 +4092,18 @@
void forEachExtensionInScope(void Function(ExtensionBuilder) f) {
if (_extensionsInScope == null) {
_extensionsInScope = <ExtensionBuilder>{};
- scope.forEachExtension(_extensionsInScope.add);
+ scope.forEachExtension((e) {
+ if (!e.extension.isExtensionTypeDeclaration) {
+ _extensionsInScope.add(e);
+ }
+ });
if (_prefixBuilders != null) {
for (PrefixBuilder prefix in _prefixBuilders) {
- prefix.exportScope.forEachExtension(_extensionsInScope.add);
+ prefix.exportScope.forEachExtension((e) {
+ if (!e.extension.isExtensionTypeDeclaration) {
+ _extensionsInScope.add(e);
+ }
+ });
}
}
}
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index e88b901..2a53afb 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -276,6 +276,7 @@
erased
err
esc
+et
everytime
evicting
exceed
diff --git a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart
index 114ac6f..9ecf985 100644
--- a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart
+++ b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart
@@ -10,11 +10,22 @@
double get bar => 3.14;
}
-test(A a, E e) {
+extension type ET on A {
+ String get baz => "baz";
+}
+
+test(A a, E e, ET et) {
a.foo; // Ok.
a.bar; // Ok.
+ a.baz; // Error.
+
e.foo; // Error.
e.bar; // Ok.
+ e.baz; // Error.
+
+ et.foo; // Error.
+ et.bar; // Error.
+ et.baz; // Ok.
}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.strong.expect
index f7bc273..b0091c5 100644
--- a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.strong.expect
@@ -2,11 +2,32 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:16:5: Error: The getter 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:20:5: Error: The getter 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_getter_resolution.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+// a.baz; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:22:5: Error: The getter 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
// e.foo; // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:24:5: Error: The getter 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+// e.baz; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:26:6: Error: The getter 'foo' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+// et.foo; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:27:6: Error: The getter 'bar' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+// et.bar; // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -20,15 +41,38 @@
extension E on self::A {
get bar = self::E|get#bar;
}
+extension type ET on self::A {
+ get baz = self::ET|get#baz;
+}
static method E|get#bar(lowered final self::A #this) → core::double
return 3.14;
-static method test(self::A a, self::E e) → dynamic {
+static method ET|get#baz(lowered final self::A #this) → core::String
+ return "baz";
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::foo}{core::int};
self::E|get#bar(a);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:16:5: Error: The getter 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:20:5: Error: The getter 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_getter_resolution.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+ a.baz; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:22:5: Error: The getter 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
e.foo; // Error.
^^^";
self::E|get#bar(e);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:24:5: Error: The getter 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+ e.baz; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:26:6: Error: The getter 'foo' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+ et.foo; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:27:6: Error: The getter 'bar' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+ et.bar; // Error.
+ ^^^";
+ self::ET|get#baz(et);
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.textual_outline.expect
index 587163f..643c52f 100644
--- a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.textual_outline.expect
@@ -1,10 +1,11 @@
class A {
int get foo => 42;
}
-
extension E on A {
double get bar => 3.14;
}
-
-test(A a, E e) {}
+extension type ET on A {
+ String get baz => "baz";
+}
+test(A a, E e, ET et) {}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.expect
index f7bc273..b0091c5 100644
--- a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.expect
@@ -2,11 +2,32 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:16:5: Error: The getter 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:20:5: Error: The getter 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_getter_resolution.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+// a.baz; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:22:5: Error: The getter 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
// e.foo; // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:24:5: Error: The getter 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+// e.baz; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:26:6: Error: The getter 'foo' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+// et.foo; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:27:6: Error: The getter 'bar' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+// et.bar; // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -20,15 +41,38 @@
extension E on self::A {
get bar = self::E|get#bar;
}
+extension type ET on self::A {
+ get baz = self::ET|get#baz;
+}
static method E|get#bar(lowered final self::A #this) → core::double
return 3.14;
-static method test(self::A a, self::E e) → dynamic {
+static method ET|get#baz(lowered final self::A #this) → core::String
+ return "baz";
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::foo}{core::int};
self::E|get#bar(a);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:16:5: Error: The getter 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:20:5: Error: The getter 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_getter_resolution.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+ a.baz; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:22:5: Error: The getter 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
e.foo; // Error.
^^^";
self::E|get#bar(e);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:24:5: Error: The getter 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'baz'.
+ e.baz; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:26:6: Error: The getter 'foo' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+ et.foo; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_getter_resolution.dart:27:6: Error: The getter 'bar' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+ et.bar; // Error.
+ ^^^";
+ self::ET|get#baz(et);
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.outline.expect
index 08cef61..23219b8 100644
--- a/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_getter_resolution.dart.weak.outline.expect
@@ -11,9 +11,14 @@
extension E on self::A {
get bar = self::E|get#bar;
}
+extension type ET on self::A {
+ get baz = self::ET|get#baz;
+}
static method E|get#bar(lowered final self::A #this) → core::double
;
-static method test(self::A a, self::E e) → dynamic
+static method ET|get#baz(lowered final self::A #this) → core::String
+ ;
+static method test(self::A a, self::E e, self::ET et) → dynamic
;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart
index 0406a33..d53964e 100644
--- a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart
@@ -10,11 +10,22 @@
void bar() => foo();
}
-test(A a, E e) {
+extension type ET on A {
+ void baz() => foo();
+}
+
+test(A a, E e, ET et) {
a.foo(); // Ok.
a.bar(); // Ok.
+ a.baz(); // Error.
+
e.foo(); // Error.
e.bar(); // Ok.
+ e.baz(); // Error.
+
+ et.foo(); // Error.
+ et.bar(); // Error.
+ et.baz(); // Ok.
}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect
index 043030d..d468a09 100644
--- a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect
@@ -2,11 +2,32 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:20:5: Error: The method 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_method_resolution.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'baz'.
+// a.baz(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:22:5: Error: The method 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
// e.foo(); // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:24:5: Error: The method 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'baz'.
+// e.baz(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:26:6: Error: The method 'foo' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+// et.foo(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:27:6: Error: The method 'bar' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing method, or defining a method name 'bar'.
+// et.bar(); // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -20,17 +41,43 @@
method bar = self::E|bar;
tearoff bar = self::E|get#bar;
}
+extension type ET on self::A {
+ method baz = self::ET|baz;
+ tearoff baz = self::ET|get#baz;
+}
static method E|bar(lowered final self::A #this) → void
return #this.{self::A::foo}(){() → void};
static method E|get#bar(lowered final self::A #this) → () → void
return () → void => self::E|bar(#this);
-static method test(self::A a, self::E e) → dynamic {
+static method ET|baz(lowered final self::A #this) → void
+ return #this.{self::A::foo}(){() → void};
+static method ET|get#baz(lowered final self::A #this) → () → void
+ return () → void => self::ET|baz(#this);
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::foo}(){() → void};
self::E|bar(a);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:20:5: Error: The method 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_method_resolution.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'baz'.
+ a.baz(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:22:5: Error: The method 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing method, or defining a method name 'foo'.
e.foo(); // Error.
^^^";
self::E|bar(e);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:24:5: Error: The method 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'baz'.
+ e.baz(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:26:6: Error: The method 'foo' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+ et.foo(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:27:6: Error: The method 'bar' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing method, or defining a method name 'bar'.
+ et.bar(); // Error.
+ ^^^";
+ self::ET|baz(et);
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect
index d2f4abf..2bc13be 100644
--- a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect
@@ -1,10 +1,11 @@
class A {
void foo() {}
}
-
extension E on A {
void bar() => foo();
}
-
-test(A a, E e) {}
+extension type ET on A {
+ void baz() => foo();
+}
+test(A a, E e, ET et) {}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect
index 043030d..d468a09 100644
--- a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect
@@ -2,11 +2,32 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:20:5: Error: The method 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_method_resolution.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'baz'.
+// a.baz(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:22:5: Error: The method 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
// e.foo(); // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:24:5: Error: The method 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'baz'.
+// e.baz(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:26:6: Error: The method 'foo' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+// et.foo(); // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:27:6: Error: The method 'bar' isn't defined for the extension 'ET'.
+// Try correcting the name to the name of an existing method, or defining a method name 'bar'.
+// et.bar(); // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -20,17 +41,43 @@
method bar = self::E|bar;
tearoff bar = self::E|get#bar;
}
+extension type ET on self::A {
+ method baz = self::ET|baz;
+ tearoff baz = self::ET|get#baz;
+}
static method E|bar(lowered final self::A #this) → void
return #this.{self::A::foo}(){() → void};
static method E|get#bar(lowered final self::A #this) → () → void
return () → void => self::E|bar(#this);
-static method test(self::A a, self::E e) → dynamic {
+static method ET|baz(lowered final self::A #this) → void
+ return #this.{self::A::foo}(){() → void};
+static method ET|get#baz(lowered final self::A #this) → () → void
+ return () → void => self::ET|baz(#this);
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::foo}(){() → void};
self::E|bar(a);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:20:5: Error: The method 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_method_resolution.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'baz'.
+ a.baz(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:22:5: Error: The method 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing method, or defining a method name 'foo'.
e.foo(); // Error.
^^^";
self::E|bar(e);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:24:5: Error: The method 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'baz'.
+ e.baz(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:26:6: Error: The method 'foo' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+ et.foo(); // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:27:6: Error: The method 'bar' isn't defined for the extension 'ET'.
+Try correcting the name to the name of an existing method, or defining a method name 'bar'.
+ et.bar(); // Error.
+ ^^^";
+ self::ET|baz(et);
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect
index e77d076..6072cb8 100644
--- a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect
@@ -12,11 +12,19 @@
method bar = self::E|bar;
tearoff bar = self::E|get#bar;
}
+extension type ET on self::A {
+ method baz = self::ET|baz;
+ tearoff baz = self::ET|get#baz;
+}
static method E|bar(lowered final self::A #this) → void
;
static method E|get#bar(lowered final self::A #this) → () → void
return () → void => self::E|bar(#this);
-static method test(self::A a, self::E e) → dynamic
+static method ET|baz(lowered final self::A #this) → void
+ ;
+static method ET|get#baz(lowered final self::A #this) → () → void
+ return () → void => self::ET|baz(#this);
+static method test(self::A a, self::E e, self::ET et) → dynamic
;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart
index 7f1f10b..ace84f6 100644
--- a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart
+++ b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart
@@ -13,18 +13,31 @@
dynamic operator+(dynamic other) => 42;
}
-test(A a, E e) {
+extension type ET on A {
+ dynamic operator~/(dynamic other) => 42;
+}
+
+test(A a, E e, ET et) {
a * "foobar"; // Ok.
a[0]; // Ok.
a[0] = "foobar"; // Ok.
-a; // Ok.
a + "foobar"; // Ok.
+ a ~/ "foobar"; // Error.
e * "foobar"; // Error.
e[0]; // Error.
e[0] = "foobar"; // Error.
-e; // Error.
e + "foobar"; // Ok.
+ e ~/ "foobar"; // Error.
+
+ et * "foobar"; // Error.
+ et[0]; // Error.
+ et[0] = "foobar"; // Error.
+ -et; // Error.
+ et + "foobar"; // Error.
+ et ~/ "foobar"; // Ok.
}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.strong.expect
index 2ff87ce..743deb8 100644
--- a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.strong.expect
@@ -2,26 +2,62 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:23:5: Error: The operator '*' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:5: Error: The operator '~/' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_operator_resolution.dart'.
+// Try correcting the operator to an existing operator, or defining a '~/' operator.
+// a ~/ "foobar"; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:28:5: Error: The operator '*' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '*' operator.
// e * "foobar"; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:24:4: Error: The operator '[]' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:29:4: Error: The operator '[]' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '[]' operator.
// e[0]; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:25:4: Error: The operator '[]=' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:30:4: Error: The operator '[]=' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '[]=' operator.
// e[0] = "foobar"; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:31:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
// -e; // Error.
// ^
//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:33:5: Error: The operator '~/' isn't defined for the extension 'E'.
+// Try correcting the operator to an existing operator, or defining a '~/' operator.
+// e ~/ "foobar"; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:35:6: Error: The operator '*' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '*' operator.
+// et * "foobar"; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:36:5: Error: The operator '[]' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '[]' operator.
+// et[0]; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:37:5: Error: The operator '[]=' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '[]=' operator.
+// et[0] = "foobar"; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:38:3: Error: The operator 'unary-' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+// -et; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:39:6: Error: The operator '+' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '+' operator.
+// et + "foobar"; // Error.
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -40,30 +76,65 @@
extension E on self::A {
operator + = self::E|+;
}
+extension type ET on self::A {
+ operator ~/ = self::ET|~/;
+}
static method E|+(lowered final self::A #this, dynamic other) → dynamic
return 42;
-static method test(self::A a, self::E e) → dynamic {
+static method ET|~/(lowered final self::A #this, dynamic other) → dynamic
+ return 42;
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::*}("foobar"){(dynamic) → dynamic};
a.{self::A::[]}(0){(core::int) → dynamic};
a.{self::A::[]=}(0, "foobar"){(core::int, dynamic) → void};
a.{self::A::unary-}(){() → dynamic};
self::E|+(a, "foobar");
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:23:5: Error: The operator '*' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:5: Error: The operator '~/' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_operator_resolution.dart'.
+Try correcting the operator to an existing operator, or defining a '~/' operator.
+ a ~/ \"foobar\"; // Error.
+ ^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:28:5: Error: The operator '*' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '*' operator.
e * \"foobar\"; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:24:4: Error: The operator '[]' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:29:4: Error: The operator '[]' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '[]' operator.
e[0]; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:25:4: Error: The operator '[]=' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:30:4: Error: The operator '[]=' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '[]=' operator.
e[0] = \"foobar\"; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:31:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a 'unary-' operator.
-e; // Error.
^";
self::E|+(e, "foobar");
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:33:5: Error: The operator '~/' isn't defined for the extension 'E'.
+Try correcting the operator to an existing operator, or defining a '~/' operator.
+ e ~/ \"foobar\"; // Error.
+ ^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:35:6: Error: The operator '*' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '*' operator.
+ et * \"foobar\"; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:36:5: Error: The operator '[]' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '[]' operator.
+ et[0]; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:37:5: Error: The operator '[]=' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '[]=' operator.
+ et[0] = \"foobar\"; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:38:3: Error: The operator 'unary-' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+ -et; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:39:6: Error: The operator '+' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '+' operator.
+ et + \"foobar\"; // Error.
+ ^";
+ self::ET|~/(et, "foobar");
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.textual_outline.expect
index b773643..d324d2b 100644
--- a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.textual_outline.expect
@@ -1,13 +1,14 @@
class A {
- dynamic operator *(dynamic other) => 42;
- dynamic operator [](int index) => 42;
- void operator []=(int index, dynamic value) {}
- dynamic operator -() => 42;
+ dynamic operator*(dynamic other) => 42;
+ dynamic operator[](int index) => 42;
+ void operator[]=(int index, dynamic value) {}
+ dynamic operator-() => 42;
}
-
extension E on A {
- dynamic operator +(dynamic other) => 42;
+ dynamic operator+(dynamic other) => 42;
}
-
-test(A a, E e) {}
+extension type ET on A {
+ dynamic operator~/(dynamic other) => 42;
+}
+test(A a, E e, ET et) {}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.expect
index 2ff87ce..743deb8 100644
--- a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.expect
@@ -2,26 +2,62 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:23:5: Error: The operator '*' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:5: Error: The operator '~/' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_operator_resolution.dart'.
+// Try correcting the operator to an existing operator, or defining a '~/' operator.
+// a ~/ "foobar"; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:28:5: Error: The operator '*' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '*' operator.
// e * "foobar"; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:24:4: Error: The operator '[]' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:29:4: Error: The operator '[]' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '[]' operator.
// e[0]; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:25:4: Error: The operator '[]=' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:30:4: Error: The operator '[]=' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a '[]=' operator.
// e[0] = "foobar"; // Error.
// ^
//
-// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:31:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
// -e; // Error.
// ^
//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:33:5: Error: The operator '~/' isn't defined for the extension 'E'.
+// Try correcting the operator to an existing operator, or defining a '~/' operator.
+// e ~/ "foobar"; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:35:6: Error: The operator '*' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '*' operator.
+// et * "foobar"; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:36:5: Error: The operator '[]' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '[]' operator.
+// et[0]; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:37:5: Error: The operator '[]=' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '[]=' operator.
+// et[0] = "foobar"; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:38:3: Error: The operator 'unary-' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+// -et; // Error.
+// ^
+//
+// pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:39:6: Error: The operator '+' isn't defined for the extension 'ET'.
+// Try correcting the operator to an existing operator, or defining a '+' operator.
+// et + "foobar"; // Error.
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -40,30 +76,65 @@
extension E on self::A {
operator + = self::E|+;
}
+extension type ET on self::A {
+ operator ~/ = self::ET|~/;
+}
static method E|+(lowered final self::A #this, dynamic other) → dynamic
return 42;
-static method test(self::A a, self::E e) → dynamic {
+static method ET|~/(lowered final self::A #this, dynamic other) → dynamic
+ return 42;
+static method test(self::A a, self::E e, self::ET et) → dynamic {
a.{self::A::*}("foobar"){(dynamic) → dynamic};
a.{self::A::[]}(0){(core::int) → dynamic};
a.{self::A::[]=}(0, "foobar"){(core::int, dynamic) → void};
a.{self::A::unary-}(){() → dynamic};
self::E|+(a, "foobar");
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:23:5: Error: The operator '*' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:5: Error: The operator '~/' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_operator_resolution.dart'.
+Try correcting the operator to an existing operator, or defining a '~/' operator.
+ a ~/ \"foobar\"; // Error.
+ ^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:28:5: Error: The operator '*' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '*' operator.
e * \"foobar\"; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:24:4: Error: The operator '[]' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:29:4: Error: The operator '[]' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '[]' operator.
e[0]; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:25:4: Error: The operator '[]=' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:30:4: Error: The operator '[]=' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a '[]=' operator.
e[0] = \"foobar\"; // Error.
^";
- invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:26:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:31:3: Error: The operator 'unary-' isn't defined for the extension 'E'.
Try correcting the operator to an existing operator, or defining a 'unary-' operator.
-e; // Error.
^";
self::E|+(e, "foobar");
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:33:5: Error: The operator '~/' isn't defined for the extension 'E'.
+Try correcting the operator to an existing operator, or defining a '~/' operator.
+ e ~/ \"foobar\"; // Error.
+ ^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:35:6: Error: The operator '*' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '*' operator.
+ et * \"foobar\"; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:36:5: Error: The operator '[]' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '[]' operator.
+ et[0]; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:37:5: Error: The operator '[]=' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '[]=' operator.
+ et[0] = \"foobar\"; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:38:3: Error: The operator 'unary-' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+ -et; // Error.
+ ^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_operator_resolution.dart:39:6: Error: The operator '+' isn't defined for the extension 'ET'.
+Try correcting the operator to an existing operator, or defining a '+' operator.
+ et + \"foobar\"; // Error.
+ ^";
+ self::ET|~/(et, "foobar");
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.outline.expect
index af29517..f6ffff4 100644
--- a/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_operator_resolution.dart.weak.outline.expect
@@ -17,9 +17,14 @@
extension E on self::A {
operator + = self::E|+;
}
+extension type ET on self::A {
+ operator ~/ = self::ET|~/;
+}
static method E|+(lowered final self::A #this, dynamic other) → dynamic
;
-static method test(self::A a, self::E e) → dynamic
+static method ET|~/(lowered final self::A #this, dynamic other) → dynamic
+ ;
+static method test(self::A a, self::E e, self::ET et) → dynamic
;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart
index 20f43d6..0205c3e 100644
--- a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart
+++ b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart
@@ -10,11 +10,22 @@
void set bar(int value) {}
}
+extension type ET on A {
+ void set baz(int value) {}
+}
+
test(A a, E e) {
a.foo = 42; // Ok.
a.bar = 42; // Ok.
+ a.baz = 42; // Error.
+
e.foo = 42; // Error.
e.bar = 42; // Ok.
+ e.baz = 42; // Error.
+
+ et.foo = 42; // Error.
+ et.bar = 42; // Error.
+ et.baz = 42; // Ok.
}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.strong.expect
index c7f4354..1ce4b82 100644
--- a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.strong.expect
@@ -2,11 +2,34 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:16:5: Error: The setter 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:26:3: Error: Getter not found: 'et'.
+// et.foo = 42; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:27:3: Error: Getter not found: 'et'.
+// et.bar = 42; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:28:3: Error: Getter not found: 'et'.
+// et.baz = 42; // Ok.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:20:5: Error: The setter 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_setter_resolution.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+// a.baz = 42; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:22:5: Error: The setter 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
// e.foo = 42; // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:24:5: Error: The setter 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+// e.baz = 42; // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -19,14 +42,36 @@
extension E on self::A {
set bar = self::E|set#bar;
}
+extension type ET on self::A {
+ set baz = self::ET|set#baz;
+}
static method E|set#bar(lowered final self::A #this, core::int value) → void {}
+static method ET|set#baz(lowered final self::A #this, core::int value) → void {}
static method test(self::A a, self::E e) → dynamic {
a.{self::A::foo} = 42;
self::E|set#bar(a, 42);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:16:5: Error: The setter 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:20:5: Error: The setter 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_setter_resolution.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+ a.baz = 42; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:22:5: Error: The setter 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
e.foo = 42; // Error.
^^^";
self::E|set#bar(e, 42);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:24:5: Error: The setter 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+ e.baz = 42; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:26:3: Error: Getter not found: 'et'.
+ et.foo = 42; // Error.
+ ^^"{dynamic}.foo = 42;
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:27:3: Error: Getter not found: 'et'.
+ et.bar = 42; // Error.
+ ^^"{dynamic}.bar = 42;
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:28:3: Error: Getter not found: 'et'.
+ et.baz = 42; // Ok.
+ ^^"{dynamic}.baz = 42;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.textual_outline.expect
index d7b5425..60eca21 100644
--- a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.textual_outline.expect
@@ -1,10 +1,11 @@
class A {
void set foo(int value) {}
}
-
extension E on A {
void set bar(int value) {}
}
-
+extension type ET on A {
+ void set baz(int value) {}
+}
test(A a, E e) {}
main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.expect
index c7f4354..1ce4b82 100644
--- a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.expect
@@ -2,11 +2,34 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:16:5: Error: The setter 'foo' isn't defined for the extension 'E'.
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:26:3: Error: Getter not found: 'et'.
+// et.foo = 42; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:27:3: Error: Getter not found: 'et'.
+// et.bar = 42; // Error.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:28:3: Error: Getter not found: 'et'.
+// et.baz = 42; // Ok.
+// ^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:20:5: Error: The setter 'baz' isn't defined for the class 'A'.
+// - 'A' is from 'pkg/front_end/testcases/extension_types/simple_setter_resolution.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+// a.baz = 42; // Error.
+// ^^^
+//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:22:5: Error: The setter 'foo' isn't defined for the extension 'E'.
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
// e.foo = 42; // Error.
// ^^^
//
+// pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:24:5: Error: The setter 'baz' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+// e.baz = 42; // Error.
+// ^^^
+//
import self as self;
import "dart:core" as core;
@@ -19,14 +42,36 @@
extension E on self::A {
set bar = self::E|set#bar;
}
+extension type ET on self::A {
+ set baz = self::ET|set#baz;
+}
static method E|set#bar(lowered final self::A #this, core::int value) → void {}
+static method ET|set#baz(lowered final self::A #this, core::int value) → void {}
static method test(self::A a, self::E e) → dynamic {
a.{self::A::foo} = 42;
self::E|set#bar(a, 42);
- invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:16:5: Error: The setter 'foo' isn't defined for the extension 'E'.
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:20:5: Error: The setter 'baz' isn't defined for the class 'A'.
+ - 'A' is from 'pkg/front_end/testcases/extension_types/simple_setter_resolution.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+ a.baz = 42; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:22:5: Error: The setter 'foo' isn't defined for the extension 'E'.
Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
e.foo = 42; // Error.
^^^";
self::E|set#bar(e, 42);
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:24:5: Error: The setter 'baz' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+ e.baz = 42; // Error.
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:26:3: Error: Getter not found: 'et'.
+ et.foo = 42; // Error.
+ ^^"{dynamic}.foo = 42;
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:27:3: Error: Getter not found: 'et'.
+ et.bar = 42; // Error.
+ ^^"{dynamic}.bar = 42;
+ invalid-expression "pkg/front_end/testcases/extension_types/simple_setter_resolution.dart:28:3: Error: Getter not found: 'et'.
+ et.baz = 42; // Ok.
+ ^^"{dynamic}.baz = 42;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.outline.expect
index 05a6bb6..191e17f 100644
--- a/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/extension_types/simple_setter_resolution.dart.weak.outline.expect
@@ -11,8 +11,13 @@
extension E on self::A {
set bar = self::E|set#bar;
}
+extension type ET on self::A {
+ set baz = self::ET|set#baz;
+}
static method E|set#bar(lowered final self::A #this, core::int value) → void
;
+static method ET|set#baz(lowered final self::A #this, core::int value) → void
+ ;
static method test(self::A a, self::E e) → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 7c64966..fd8e874 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -33,6 +33,10 @@
constructor_tearoffs/unnamed_constructor: FormatterCrash
dart2js/late_fields: FormatterCrash
dart2js/late_statics: FormatterCrash
+extension_types/simple_getter_resolution: FormatterCrash
+extension_types/simple_method_resolution: FormatterCrash
+extension_types/simple_operator_resolution: FormatterCrash
+extension_types/simple_setter_resolution: FormatterCrash
extensions/extension_constructor: FormatterCrash
extensions/extension_field_with_type_parameter_usage: FormatterCrash
extensions/issue38600: FormatterCrash
diff --git a/runtime/vm/heap/freelist_test.cc b/runtime/vm/heap/freelist_test.cc
index fe6c1a4..4e7b7f4 100644
--- a/runtime/vm/heap/freelist_test.cc
+++ b/runtime/vm/heap/freelist_test.cc
@@ -146,7 +146,8 @@
TEST_CASE(FreeListProtectedVariableSizeObjects) {
FreeList* free_list = new FreeList();
- const intptr_t kBlobSize = 8 * KB;
+ const intptr_t kBlobSize = 16 * KB;
+ ASSERT(kBlobSize >= VirtualMemory::PageSize());
const intptr_t kMinSize = 2 * kWordSize;
uword* objects = new uword[kBlobSize / kMinSize];
for (intptr_t i = 0; i < kBlobSize / kMinSize; ++i) {
@@ -155,28 +156,27 @@
VirtualMemory* blob =
VirtualMemory::Allocate(kBlobSize, /* is_executable = */ false, "test");
- ASSERT(Utils::IsAligned(blob->start(), 4096));
blob->Protect(VirtualMemory::kReadWrite);
// Enqueue the large blob as one free block.
free_list->Free(blob->start(), blob->size());
// Write protect the whole region.
- blob->Protect(VirtualMemory::kReadExecute);
+ blob->Protect(VirtualMemory::kReadOnly);
// Allocate and free objects so that free list has > 1 elements.
- uword e0 = Allocate(free_list, 1 * KB, true);
+ uword e0 = Allocate(free_list, 2 * KB, true);
ASSERT(e0);
- uword e1 = Allocate(free_list, 3 * KB, true);
+ uword e1 = Allocate(free_list, 6 * KB, true);
ASSERT(e1);
- uword e2 = Allocate(free_list, 2 * KB, true);
+ uword e2 = Allocate(free_list, 4 * KB, true);
ASSERT(e2);
- uword e3 = Allocate(free_list, 2 * KB, true);
+ uword e3 = Allocate(free_list, 4 * KB, true);
ASSERT(e3);
- Free(free_list, e1, 3 * KB, true);
- Free(free_list, e2, 2 * KB, true);
- e0 = Allocate(free_list, 3 * KB - 2 * kWordSize, true);
+ Free(free_list, e1, 6 * KB, true);
+ Free(free_list, e2, 4 * KB, true);
+ e0 = Allocate(free_list, 6 * KB - 2 * kWordSize, true);
ASSERT(e0);
// Delete the memory associated with the test.
diff --git a/sdk/lib/_internal/js_runtime/lib/constant_map.dart b/sdk/lib/_internal/js_runtime/lib/constant_map.dart
index 0f673d8..d5a5174 100644
--- a/sdk/lib/_internal/js_runtime/lib/constant_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/constant_map.dart
@@ -74,7 +74,10 @@
void addAll(Map<K, V> other) => _throwUnmodifiable();
Iterable<MapEntry<K, V>> get entries sync* {
- for (var key in keys) yield new MapEntry<K, V>(key, this[key]!);
+ // `this[key]` has static type `V?` but is always `V`. Rather than `as V`,
+ // we use `as dynamic` so the upcast requires no checking and the implicit
+ // downcast to `V` will be discarded in production.
+ for (var key in keys) yield new MapEntry<K, V>(key, this[key] as dynamic);
}
void addEntries(Iterable<MapEntry<K, V>> entries) {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 4ef1735..f06c29a 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -2342,6 +2342,12 @@
return Closure.fromTearOff(parameters);
}
+/// Base class for closures with no arguments.
+abstract class Closure0Args extends Closure {}
+
+/// Base class for closures with two positional arguments.
+abstract class Closure2Args extends Closure {}
+
/// Represents an implicit closure of a function.
abstract class TearOffClosure extends Closure {}
diff --git a/sdk/lib/internal/symbol.dart b/sdk/lib/internal/symbol.dart
index c65e5e8..718ac68 100644
--- a/sdk/lib/internal/symbol.dart
+++ b/sdk/lib/internal/symbol.dart
@@ -106,9 +106,6 @@
*/
const Symbol.unvalidated(this._name);
- // This is called by dart2js.
- Symbol.validated(String name) : this._name = validatePublicSymbol(name);
-
bool operator ==(Object other) => other is Symbol && _name == other._name;
external int get hashCode;
diff --git a/tests/web/internal/lax_runtime_type_closure_to_string1_test.dart b/tests/web/internal/lax_runtime_type_closure_to_string1_test.dart
index aed91ee..220d3c6 100644
--- a/tests/web/internal/lax_runtime_type_closure_to_string1_test.dart
+++ b/tests/web/internal/lax_runtime_type_closure_to_string1_test.dart
@@ -18,7 +18,7 @@
var toString = '${local1.runtimeType}';
if ('$Object' == 'Object') {
// `true` if non-minified.
- Expect.equals("Closure", toString);
+ Expect.equals("Closure0Args", toString);
}
print(toString);
local2(0);
diff --git a/tests/web/regress/46417_test.dart b/tests/web/regress/46417_test.dart
new file mode 100644
index 0000000..3ba7d9b
--- /dev/null
+++ b/tests/web/regress/46417_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+void main() {
+ var v = {
+ ...Map.unmodifiable({'x': null})
+ };
+ Expect.equals(null, v['x']);
+}
diff --git a/tests/web_2/internal/lax_runtime_type_closure_to_string1_test.dart b/tests/web_2/internal/lax_runtime_type_closure_to_string1_test.dart
index 51d90d5..210d320 100644
--- a/tests/web_2/internal/lax_runtime_type_closure_to_string1_test.dart
+++ b/tests/web_2/internal/lax_runtime_type_closure_to_string1_test.dart
@@ -20,7 +20,7 @@
var toString = '${local1.runtimeType}';
if ('$Object' == 'Object') {
// `true` if non-minified.
- Expect.equals("Closure", toString);
+ Expect.equals("Closure0Args", toString);
}
print(toString);
local2(0);
diff --git a/tests/web_2/regress/46417_test.dart b/tests/web_2/regress/46417_test.dart
new file mode 100644
index 0000000..3ba7d9b
--- /dev/null
+++ b/tests/web_2/regress/46417_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+void main() {
+ var v = {
+ ...Map.unmodifiable({'x': null})
+ };
+ Expect.equals(null, v['x']);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 08c8f41..d064fce 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 240
+PRERELEASE 241
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/README.md b/tools/bots/README.md
index 52dd12f..47acbc4 100644
--- a/tools/bots/README.md
+++ b/tools/bots/README.md
@@ -12,7 +12,7 @@
The test matrix is a JSON document and consists of the `"filesets"` object, the
`"configurations"` list, and the `"builder_configurations"` list as well as a
-`"global"` values object and a `"branches"` list.
+`"branches"` list.
### Filesets
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 29fe236..e9520a3 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -1,8 +1,4 @@
{
- "global": {
- "chrome": "81",
- "firefox": "67"
- },
"branches": [
"master"
],