Version 2.14.0-310.0.dev
Merge commit '21af69a7a56f0e74bc8d5cba873d2ee3bd30579f' into 'dev'
diff --git a/DEPS b/DEPS
index 9ce5a3d..44d5d82 100644
--- a/DEPS
+++ b/DEPS
@@ -103,7 +103,7 @@
# and land the review.
#
# For more details, see https://github.com/dart-lang/sdk/issues/30164
- "dart_style_rev": "0fe592042eda5d9eea6fc240a8ee0fe531bb0794",
+ "dart_style_rev": "9d9dff90d9a2e0793ad2f795f36c2777f720eda0",
"dartdoc_rev" : "c9621b92c738ec21a348cc2de032858276e9c774",
"devtools_rev" : "64cffbed6366329ad05e44d48fa2298367643bb6",
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 5dc3f5b..e49f3a2e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -11,6 +11,7 @@
import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:kernel/ast.dart';
+import 'package:kernel/type_algebra.dart';
import '../builder/builder.dart';
import '../builder/class_builder.dart';
@@ -24,6 +25,7 @@
import '../builder/type_alias_builder.dart';
import '../builder/type_builder.dart';
import '../builder/type_declaration_builder.dart';
+import '../builder/type_variable_builder.dart';
import '../builder/unresolved_type.dart';
import '../constant_context.dart' show ConstantContext;
@@ -3099,6 +3101,7 @@
TypeDeclarationBuilder? declarationBuilder = declaration;
TypeAliasBuilder? aliasBuilder;
List<TypeBuilder>? unaliasedTypeArguments;
+ bool isGenericTypedefTearOff = false;
if (declarationBuilder is TypeAliasBuilder) {
aliasBuilder = declarationBuilder;
declarationBuilder = aliasBuilder.unaliasDeclaration(null,
@@ -3129,6 +3132,19 @@
..fileUri = _uri
..offset = fileOffset);
}
+ if (aliasedTypeArguments == null &&
+ aliasBuilder.typeVariablesCount != 0) {
+ isGenericTypedefTearOff = true;
+ aliasedTypeArguments = <TypeBuilder>[];
+ for (TypeVariableBuilder typeVariable
+ in aliasBuilder.typeVariables!) {
+ aliasedTypeArguments.add(new NamedTypeBuilder(typeVariable.name,
+ const NullabilityBuilder.omitted(), null, _uri, fileOffset)
+ ..bind(typeVariable));
+ }
+ }
+ unaliasedTypeArguments =
+ aliasBuilder.unaliasTypeArguments(aliasedTypeArguments);
}
}
}
@@ -3177,10 +3193,31 @@
builtTypeArguments =
_helper.buildDartTypeArguments(typeArguments);
}
- return builtTypeArguments != null && builtTypeArguments.isNotEmpty
- ? _helper.forest.createInstantiation(
- token.charOffset, tearOffExpression, builtTypeArguments)
- : tearOffExpression;
+ if (isGenericTypedefTearOff) {
+ FreshTypeParameters freshTypeParameters =
+ getFreshTypeParameters(
+ aliasBuilder!.typedef.typeParameters);
+ List<DartType>? substitutedTypeArguments;
+ if (builtTypeArguments != null) {
+ substitutedTypeArguments = <DartType>[];
+ for (DartType builtTypeArgument in builtTypeArguments) {
+ substitutedTypeArguments
+ .add(freshTypeParameters.substitute(builtTypeArgument));
+ }
+ }
+ tearOffExpression = _helper.forest.createTypedefTearOff(
+ token.charOffset,
+ freshTypeParameters.freshTypeParameters,
+ tearOffExpression,
+ substitutedTypeArguments ?? const <DartType>[]);
+ } else {
+ if (builtTypeArguments != null &&
+ builtTypeArguments.isNotEmpty) {
+ tearOffExpression = _helper.forest.createInstantiation(
+ token.charOffset, tearOffExpression, builtTypeArguments);
+ }
+ }
+ return tearOffExpression;
}
}
generator = new UnresolvedNameGenerator(_helper, send.token, name);
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 0a6909a..19e7096 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -846,6 +846,17 @@
return new Instantiation(expression, typeArguments)
..fileOffset = fileOffset;
}
+
+ TypedefTearOff createTypedefTearOff(
+ int fileOffset,
+ List<TypeParameter> typeParameters,
+ Expression expression,
+ List<DartType> typeArguments) {
+ // ignore: unnecessary_null_comparison
+ assert(fileOffset != null);
+ return new TypedefTearOff(typeParameters, expression, typeArguments)
+ ..fileOffset = fileOffset;
+ }
}
class _VariablesDeclaration extends Statement {
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index d87c8f9..7fc34a9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -7,7 +7,7 @@
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/src/legacy_erasure.dart';
-import 'package:kernel/type_algebra.dart' show Substitution;
+import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../../base/instrumentation.dart'
@@ -225,7 +225,37 @@
@override
ExpressionInferenceResult visitTypedefTearOff(
TypedefTearOff node, DartType typeContext) {
- return _unhandledExpression(node, typeContext);
+ ExpressionInferenceResult expressionResult = inferrer.inferExpression(
+ node.expression, const UnknownType(), true,
+ isVoidAllowed: true);
+ node.expression = expressionResult.expression..parent = node;
+
+ assert(
+ expressionResult.inferredType is FunctionType,
+ "Expected a FunctionType from tearing off a constructor from "
+ "a typedef, but got '${expressionResult.inferredType.runtimeType}'.");
+ FunctionType expressionType = expressionResult.inferredType as FunctionType;
+
+ assert(expressionType.typeParameters.length == node.typeArguments.length);
+ Substitution substitution = Substitution.fromPairs(
+ expressionType.typeParameters, node.typeArguments);
+ FunctionType resultType = substitution
+ .substituteType(expressionType.withoutTypeParameters) as FunctionType;
+ FreshTypeParameters freshTypeParameters =
+ getFreshTypeParameters(node.typeParameters);
+ resultType = freshTypeParameters.substitute(resultType) as FunctionType;
+ resultType = new FunctionType(resultType.positionalParameters,
+ resultType.returnType, resultType.declaredNullability,
+ namedParameters: resultType.namedParameters,
+ typeParameters: freshTypeParameters.freshTypeParameters,
+ requiredParameterCount: resultType.requiredParameterCount,
+ typedefType: null);
+ ExpressionInferenceResult inferredResult =
+ inferrer.instantiateTearOff(resultType, typeContext, node);
+ Expression ensuredResultExpression =
+ inferrer.ensureAssignableResult(typeContext, inferredResult);
+ return new ExpressionInferenceResult(
+ inferredResult.inferredType, ensuredResultExpression);
}
@override
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart
index 0abf8e6..1ee6b80 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart
@@ -45,7 +45,9 @@
B<num> Function() test19() => DB3<num, String>.foo; // Ok.
B<num> Function() test20() => DB3<num, String>.bar; // Ok.
B<num> Function() test21() => DB3.new; // Ok.
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
-B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
+B<Y> Function<Y extends num, Z extends String>() test22() => DB3.new; // Ok.
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+
+B<String> Function() test24() => DB2.new; // Ok.
main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.expect
index 0a4373e..0b438b0 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.expect
@@ -15,24 +15,24 @@
// B<num> Function() test9() => DB1.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
-// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
-// ^
-//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
// B<Y> Function<Y>() test17() => DB2.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
-// ^
+// B<Y> Function<Y>() test17() => DB2.new; // Error.
+// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
// ^
//
import self as self;
@@ -63,9 +63,9 @@
static method test2() → () → self::A
return self::A::•;
static method test3() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test4() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test5() → () → self::A
return self::A::•;
static method test6() → () → self::A
@@ -90,17 +90,17 @@
static method test14() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test15() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num>.(self::B::•<X>)<core::num>;
static method test16() → <Y extends core::num = dynamic>() → self::B<Y>
- return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic>() → self::B<Y>;
+ return <X extends core::num>.(self::B::•<X>);
static method test17() → <Y extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+ return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
B<Y> Function<Y>() test17() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
+ ^" in (let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y>() test17() => DB2.new; // Error.
+ ^" in (<X extends core::num>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
static method test18() → () → self::B<core::num>
return self::B::•<core::num>;
static method test19() → () → self::B<core::num>
@@ -108,15 +108,17 @@
static method test20() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test21() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)<core::num, core::String>;
static method test22() → <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>
- return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>);
static method test23() → <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+ return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (<X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+static method test24() → () → self::B<core::String>
+ return <X extends core::num>.(self::B::•<X>)<Never>;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.transformed.expect
index 0a4373e..876caac 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.strong.transformed.expect
@@ -15,24 +15,24 @@
// B<num> Function() test9() => DB1.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
-// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
-// ^
-//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
// B<Y> Function<Y>() test17() => DB2.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
-// ^
+// B<Y> Function<Y>() test17() => DB2.new; // Error.
+// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
// ^
//
import self as self;
@@ -63,9 +63,9 @@
static method test2() → () → self::A
return self::A::•;
static method test3() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test4() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test5() → () → self::A
return self::A::•;
static method test6() → () → self::A
@@ -90,17 +90,17 @@
static method test14() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test15() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num>.(self::B::•<X>)<core::num>;
static method test16() → <Y extends core::num = dynamic>() → self::B<Y>
- return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic>() → self::B<Y>;
+ return <X extends core::num>.(self::B::•<X>);
static method test17() → <Y extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+ return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
B<Y> Function<Y>() test17() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
+ ^" in let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y>() test17() => DB2.new; // Error.
+ ^" in (<X extends core::num>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
static method test18() → () → self::B<core::num>
return self::B::•<core::num>;
static method test19() → () → self::B<core::num>
@@ -108,15 +108,17 @@
static method test20() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test21() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)<core::num, core::String>;
static method test22() → <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>
- return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>);
static method test23() → <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+ return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (<X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+static method test24() → () → self::B<core::String>
+ return <X extends core::num>.(self::B::•<X>)<Never>;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.textual_outline.expect
index fe0d7be..c3a7ab9 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.textual_outline.expect
@@ -30,6 +30,7 @@
B<num> Function() test19() => DB3<num, String>.foo;
B<num> Function() test20() => DB3<num, String>.bar;
B<num> Function() test21() => DB3.new;
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new;
-B<Y> Function<Y, Z>() test23() => DB2.new;
+B<Y> Function<Y extends num, Z extends String>() test22() => DB3.new;
+B<Y> Function<Y, Z>() test23() => DB3.new;
+B<String> Function() test24() => DB2.new;
main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.expect
index 0a4373e..0b438b0 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.expect
@@ -15,24 +15,24 @@
// B<num> Function() test9() => DB1.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
-// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
-// ^
-//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
// B<Y> Function<Y>() test17() => DB2.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
-// ^
+// B<Y> Function<Y>() test17() => DB2.new; // Error.
+// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
// ^
//
import self as self;
@@ -63,9 +63,9 @@
static method test2() → () → self::A
return self::A::•;
static method test3() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test4() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test5() → () → self::A
return self::A::•;
static method test6() → () → self::A
@@ -90,17 +90,17 @@
static method test14() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test15() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num>.(self::B::•<X>)<core::num>;
static method test16() → <Y extends core::num = dynamic>() → self::B<Y>
- return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic>() → self::B<Y>;
+ return <X extends core::num>.(self::B::•<X>);
static method test17() → <Y extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+ return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
B<Y> Function<Y>() test17() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
+ ^" in (let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y>() test17() => DB2.new; // Error.
+ ^" in (<X extends core::num>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
static method test18() → () → self::B<core::num>
return self::B::•<core::num>;
static method test19() → () → self::B<core::num>
@@ -108,15 +108,17 @@
static method test20() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test21() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)<core::num, core::String>;
static method test22() → <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>
- return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>);
static method test23() → <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+ return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (<X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+static method test24() → () → self::B<core::String>
+ return <X extends core::num>.(self::B::•<X>)<Never>;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.outline.expect
index 7110e07..fda6d4f 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.outline.expect
@@ -65,5 +65,7 @@
;
static method test23() → <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>
;
+static method test24() → () → self::B<core::String>
+ ;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.transformed.expect
index 0a4373e..876caac 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart.weak.transformed.expect
@@ -15,24 +15,24 @@
// B<num> Function() test9() => DB1.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
-// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
-// ^
-//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
// B<Y> Function<Y>() test17() => DB2.new; // Error.
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
-// ^
+// B<Y> Function<Y>() test17() => DB2.new; // Error.
+// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-// B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+// - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+// B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
// ^
//
import self as self;
@@ -63,9 +63,9 @@
static method test2() → () → self::A
return self::A::•;
static method test3() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test4() → () → self::A
- return self::A::•;
+ return <unrelated X extends core::num>.(self::A::•)<core::num>;
static method test5() → () → self::A
return self::A::•;
static method test6() → () → self::A
@@ -90,17 +90,17 @@
static method test14() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test15() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num>.(self::B::•<X>)<core::num>;
static method test16() → <Y extends core::num = dynamic>() → self::B<Y>
- return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:41:44: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num>() test16() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic>() → self::B<Y>;
+ return <X extends core::num>.(self::B::•<X>);
static method test17() → <Y extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
+ return let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be returned from a function with return type 'B<Y> Function<Y>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
B<Y> Function<Y>() test17() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
+ ^" in let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:42:32: Error: A value of type 'B<X> Function<X extends num>()' can't be assigned to a variable of type 'B<Y> Function<Y>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y>() test17() => DB2.new; // Error.
+ ^" in (<X extends core::num>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic>() → self::B<Y%>;
static method test18() → () → self::B<core::num>
return self::B::•<core::num>;
static method test19() → () → self::B<core::num>
@@ -108,15 +108,17 @@
static method test20() → () → self::B<core::num>
return self::B::bar<core::num>;
static method test21() → () → self::B<core::num>
- return self::B::•<core::num>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)<core::num, core::String>;
static method test22() → <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>
- return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:48:62: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y extends num, Z extends String>()'.
- - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y extends num, Z extends String>() test22() => DB2.new; // Ok.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::num = dynamic, Z extends core::String = dynamic>() → self::B<Y>;
+ return <X extends core::num, unrelated Y extends core::String>.(self::B::•<X>);
static method test23() → <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>
- return let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<num> Function()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
+ return let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be returned from a function with return type 'B<Y> Function<Y, Z>()'.
- 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
-B<Y> Function<Y, Z>() test23() => DB2.new; // Error.
- ^" in (self::B::•<core::num>) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart:49:35: Error: A value of type 'B<X> Function<X extends num, Y extends String>()' can't be assigned to a variable of type 'B<Y> Function<Y, Z>()'.
+ - 'B' is from 'pkg/front_end/testcases/constructor_tearoffs/typedef_tearoffs.dart'.
+B<Y> Function<Y, Z>() test23() => DB3.new; // Error.
+ ^" in (<X extends core::num, unrelated Y extends core::String>.(self::B::•<X>)) as{TypeError,ForNonNullableByDefault} <Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>() → self::B<Y%>;
+static method test24() → () → self::B<core::String>
+ return <X extends core::num>.(self::B::•<X>)<Never>;
static method main() → dynamic {}
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 4c7f24f..69b540a 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -8729,9 +8729,11 @@
@override
void toTextInternal(AstPrinter printer) {
- printer.writeExpression(expression);
printer.writeTypeParameters(typeParameters);
+ printer.write(".(");
+ printer.writeExpression(expression);
printer.writeTypeArguments(typeArguments);
+ printer.write(")");
}
}
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 5460a6e..9018db9 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1615,9 +1615,11 @@
@override
void visitTypedefTearOff(TypedefTearOff node) {
writeByte(Tag.TypedefTearOff);
+ enterScope(typeParameters: node.typeParameters);
writeNodeList(node.typeParameters);
writeNode(node.expression);
writeNodeList(node.typeArguments);
+ leaveScope(typeParameters: node.typeParameters);
}
@override
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 197bdfa..53fbe25 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -2055,6 +2055,20 @@
writeMemberReferenceFromReference(node.constructorReference);
}
+ visitTypedefTearOff(TypedefTearOff node) {
+ writeTypeParameterList(node.typeParameters);
+ state = SYMBOL;
+ writeSymbol('.(');
+ writeNode(node.expression);
+ if (node.typeArguments.isNotEmpty) {
+ writeSymbol('<');
+ writeList(node.typeArguments, writeType);
+ writeSymbol('>');
+ }
+ writeSymbol(')');
+ state = WORD;
+ }
+
visitExpressionStatement(ExpressionStatement node) {
writeIndentation();
writeExpression(node.expression);
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index aec9d76..15a52eb 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -635,6 +635,13 @@
}
}
+ @override
+ void visitTypedefTearOff(TypedefTearOff node) {
+ declareTypeParameters(node.typeParameters);
+ super.visitTypedefTearOff(node);
+ undeclareTypeParameters(node.typeParameters);
+ }
+
void checkTargetedInvocation(Member target, InvocationExpression node) {
visitChildren(node);
// ignore: unnecessary_null_comparison
diff --git a/pkg/vm/lib/transformations/ffi_native.dart b/pkg/vm/lib/transformations/ffi_native.dart
index f3fdb03..4c71d56 100644
--- a/pkg/vm/lib/transformations/ffi_native.dart
+++ b/pkg/vm/lib/transformations/ffi_native.dart
@@ -72,14 +72,14 @@
// Transform:
// @FfiNative<Double Function(Double)>('Math_sqrt')
- // external double _sqrt(double x);
+ // external double _square_root(double x);
//
// Into:
- // final _@FfiNative_Math_sqrt =
+ // final _@FfiNative__square_root =
// Pointer<NativeFunction<Double Function(Double)>>
// .fromAddress(_ffi_resolver('dart:math', 'Math_sqrt'))
// .asFunction<double Function(double)>();
- // double _sqrt(double x) => _@FfiNative_Math_sqrt(x);
+ // double _square_root(double x) => _@FfiNative__square_root(x);
Statement transformFfiNative(
Procedure node, InstanceConstant annotationConst) {
assert(currentLibrary != null);
@@ -119,8 +119,8 @@
final asFunctionInvocation = StaticInvocation(asFunctionProcedure,
Arguments([fromAddressInvocation], types: [nativeType, dartType]));
- // final _@FfiNative_Math_sqrt = ...
- final fieldName = Name('_@FfiNative_${functionName.value}', currentLibrary);
+ // final _@FfiNative__square_root = ...
+ final fieldName = Name('_@FfiNative_${node.name.text}', currentLibrary);
final funcPtrField = Field.immutable(fieldName,
type: dartType,
initializer: asFunctionInvocation,
@@ -130,7 +130,7 @@
getterReference: currentLibraryIndex?.lookupGetterReference(fieldName));
currentLibrary!.addField(funcPtrField);
- // _@FfiNative_Math_sqrt(x)
+ // _@FfiNative__square_root(x)
final callFuncPtrInvocation = FunctionInvocation(
FunctionAccessKind.FunctionType,
StaticGet(funcPtrField),
@@ -144,7 +144,7 @@
visitProcedure(Procedure node) {
// Only transform functions that are external and have FfiNative annotation:
// @FfiNative<Double Function(Double)>('Math_sqrt')
- // external double _sqrt(double x);
+ // external double _square_root(double x);
if (!node.isExternal) {
return node;
}
diff --git a/runtime/platform/atomic.h b/runtime/platform/atomic.h
index ffb5bdc..98bc900 100644
--- a/runtime/platform/atomic.h
+++ b/runtime/platform/atomic.h
@@ -21,16 +21,9 @@
T load(std::memory_order order = std::memory_order_relaxed) const {
return value_.load(order);
}
- T load(std::memory_order order = std::memory_order_relaxed) const volatile {
- return value_.load(order);
- }
void store(T arg, std::memory_order order = std::memory_order_relaxed) {
value_.store(arg, order);
}
- void store(T arg,
- std::memory_order order = std::memory_order_relaxed) volatile {
- value_.store(arg, order);
- }
T fetch_add(T arg, std::memory_order order = std::memory_order_relaxed) {
return value_.fetch_add(arg, order);
@@ -51,12 +44,6 @@
std::memory_order order = std::memory_order_relaxed) {
return value_.compare_exchange_weak(expected, desired, order, order);
}
- bool compare_exchange_weak(
- T& expected, // NOLINT
- T desired,
- std::memory_order order = std::memory_order_relaxed) volatile {
- return value_.compare_exchange_weak(expected, desired, order, order);
- }
bool compare_exchange_strong(
T& expected, // NOLINT
T desired,
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 57b9e6d2..4ea2271 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -792,20 +792,16 @@
}
intptr_t source_address = reloc.source_offset;
if (reloc.source_symbol != nullptr) {
- if (strcmp(reloc.source_symbol, ".") == 0) {
- source_address += section_start + offset + reloc.section_offset;
- } else {
- auto* const source_symbol = symtab.Find(reloc.source_symbol);
- ASSERT(source_symbol != nullptr);
- source_address += source_symbol->offset;
- }
+ auto* const source_symbol = symtab.Find(reloc.source_symbol);
+ ASSERT(source_symbol != nullptr);
+ source_address += source_symbol->offset;
+ } else {
+ source_address += section_start + offset + reloc.section_offset;
}
ASSERT(reloc.size_in_bytes <= kWordSize);
word to_write = reloc.target_offset - source_address;
if (reloc.target_symbol != nullptr) {
- if (strcmp(reloc.target_symbol, ".") == 0) {
- to_write += section_start + offset + reloc.section_offset;
- } else if (auto* const symbol = symtab.Find(reloc.target_symbol)) {
+ if (auto* const symbol = symtab.Find(reloc.target_symbol)) {
to_write += symbol->offset;
} else {
ASSERT_EQUAL(strcmp(reloc.target_symbol, kSnapshotBuildIdAsmSymbol),
@@ -818,6 +814,8 @@
// InstructionsSection when there is no build ID.
to_write = Image::kNoRelocatedAddress;
}
+ } else {
+ to_write += section_start + offset + reloc.section_offset;
}
ASSERT(Utils::IsInt(reloc.size_in_bytes * kBitsPerByte, to_write));
stream->WriteBytes(reinterpret_cast<const uint8_t*>(&to_write),
@@ -1249,12 +1247,12 @@
void OffsetFromSymbol(const char* symbol, intptr_t offset) {
relocations_->Add(
- {kAddressSize, stream_->Position(), nullptr, 0, symbol, offset});
+ {kAddressSize, stream_->Position(), "", 0, symbol, offset});
addr(0); // Resolved later.
}
template <typename T>
void RelativeSymbolOffset(const char* symbol) {
- relocations_->Add({sizeof(T), stream_->Position(), ".", 0, symbol, 0});
+ relocations_->Add({sizeof(T), stream_->Position(), nullptr, 0, symbol, 0});
stream_->WriteFixed<T>(0); // Resolved later.
}
void InitializeAbstractOrigins(intptr_t size) {
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index 19400f7..579c49f 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -51,9 +51,10 @@
// Stores the information needed to appropriately generate a
// relocation from the target to the source at the given section offset.
- // If a given symbol is nullptr, then the offset is absolute (from 0).
- // Both source and target symbols could be "." which is pseudosymbol
- // corresponding to the location of the relocation itself.
+ // If a given symbol name is nullptr, then the corresponding offset is
+ // relative from the location of the relocation itself.
+ // If a given symbol name is "", then the corresponding offset is relative to
+ // the start of the snapshot.
struct Relocation {
size_t size_in_bytes;
intptr_t section_offset;
diff --git a/runtime/vm/heap/safepoint.cc b/runtime/vm/heap/safepoint.cc
index 52da48b..4a7e5de 100644
--- a/runtime/vm/heap/safepoint.cc
+++ b/runtime/vm/heap/safepoint.cc
@@ -155,7 +155,7 @@
if (!Thread::IsAtSafepoint(level_, state)) {
// Send OOB message to get it to safepoint.
if (current->IsMutatorThread()) {
- current->ScheduleInterrupts(Thread::kVMInterrupt);
+ current->ScheduleInterruptsLocked(Thread::kVMInterrupt);
}
MonitorLocker sl(&parked_lock_);
num_threads_not_parked_++;
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index e465cb6..587267c 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -692,7 +692,7 @@
// 2) The BSS offset from this section.
text_offset += Relocation(text_offset, instructions_symbol, bss_symbol);
// 3) The relocated address of the instructions.
- text_offset += Relocation(text_offset, instructions_symbol);
+ text_offset += RelocatedAddress(text_offset, instructions_symbol);
// 4) The GNU build ID note offset from this section.
text_offset += Relocation(text_offset, instructions_symbol,
SectionSymbol(ProgramSection::BuildId, vm));
@@ -1221,10 +1221,7 @@
intptr_t source_offset,
const char* target_symbol,
intptr_t target_offset) {
- if (source_symbol == nullptr || target_symbol == nullptr) {
- // We can't use absolute addresses in assembly relocations.
- return WriteTargetWord(Image::kNoRelocatedAddress);
- }
+ ASSERT(source_symbol != nullptr);
ASSERT(target_symbol != nullptr);
// TODO(dartbug.com/43274): Remove once we generate consistent build IDs
@@ -1237,23 +1234,24 @@
// All relocations are word-sized.
assembly_stream_->Printf("%s ", kWordDirective);
- if (strcmp(target_symbol, current_section_symbol_) == 0 &&
- target_offset == section_offset) {
+ if (strcmp(target_symbol, current_section_symbol_) == 0) {
assembly_stream_->WriteString("(.)");
+ target_offset -= section_offset;
} else {
assembly_stream_->Printf("%s", target_symbol);
- if (target_offset != 0) {
- assembly_stream_->Printf(" + %" Pd "", target_offset);
- }
}
- if (strcmp(source_symbol, current_section_symbol_) == 0 &&
- source_offset == section_offset) {
+ if (target_offset != 0) {
+ assembly_stream_->Printf(" + %" Pd "", target_offset);
+ }
+
+ if (strcmp(source_symbol, current_section_symbol_) == 0) {
assembly_stream_->WriteString(" - (.)");
+ source_offset -= section_offset;
} else {
assembly_stream_->Printf(" - %s", source_symbol);
- if (source_offset != 0) {
- assembly_stream_->Printf(" - %" Pd "", source_offset);
- }
+ }
+ if (source_offset != 0) {
+ assembly_stream_->Printf(" - %" Pd "", source_offset);
}
assembly_stream_->WriteString("\n");
return compiler::target::kWordSize;
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 09a1555..fc2bbdd 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -397,13 +397,15 @@
// relocated address of the target section and S is the final relocated
// address of the source, the final value is:
// (T + target_offset + target_addend) - (S + source_offset)
- // If either symbol is nullptr, then the corresponding is treated as an
- // absolute address.
virtual intptr_t Relocation(intptr_t section_offset,
const char* source_symbol,
intptr_t source_offset,
const char* target_symbol,
intptr_t target_offset) = 0;
+ // Writes a target word-sized value that contains the relocated address
+ // pointed to by the given symbol.
+ virtual intptr_t RelocatedAddress(intptr_t section_offset,
+ const char* symbol) = 0;
// Creates a static symbol for the given Code object when appropriate.
virtual void AddCodeSymbol(const Code& code,
const char* symbol,
@@ -418,11 +420,6 @@
const char* target_symbol) {
return Relocation(section_offset, source_symbol, 0, target_symbol, 0);
}
- // An overload of Relocation for outputting the relocated address of the
- // target symbol at the given section offset.
- intptr_t Relocation(intptr_t section_offset, const char* target_symbol) {
- return Relocation(section_offset, nullptr, 0, target_symbol, 0);
- }
#endif
// Writes a fixed-sized value of type T to the section contents.
template <typename T>
@@ -549,6 +546,11 @@
intptr_t source_offset,
const char* target_symbol,
intptr_t target_offset);
+ virtual intptr_t RelocatedAddress(intptr_t section_offset,
+ const char* symbol) {
+ // Cannot calculate snapshot-relative addresses in assembly snapshots.
+ return WriteTargetWord(Image::kNoRelocatedAddress);
+ }
virtual void FrameUnwindPrologue();
virtual void FrameUnwindEpilogue();
virtual void AddCodeSymbol(const Code& code,
@@ -599,6 +601,11 @@
intptr_t source_offset,
const char* target_symbol,
intptr_t target_offset);
+ virtual intptr_t RelocatedAddress(intptr_t section_offset,
+ const char* target_symbol) {
+ // ELF symbol tables always have a reserved symbol with name "" and value 0.
+ return ImageWriter::Relocation(section_offset, "", target_symbol);
+ }
virtual void AddCodeSymbol(const Code& code,
const char* symbol,
intptr_t offset);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 8993e5f..cb00d29 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -867,6 +867,19 @@
return Isolate::IsSystemIsolate(isolate);
}
+NoOOBMessageScope::NoOOBMessageScope(Thread* thread)
+ : ThreadStackResource(thread) {
+ if (thread->isolate() != nullptr) {
+ thread->DeferOOBMessageInterrupts();
+ }
+}
+
+NoOOBMessageScope::~NoOOBMessageScope() {
+ if (thread()->isolate() != nullptr) {
+ thread()->RestoreOOBMessageInterrupts();
+ }
+}
+
Bequest::~Bequest() {
if (handle_ == nullptr) {
return;
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 4c2d9f5..c17a81d 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -134,6 +134,16 @@
DISALLOW_COPY_AND_ASSIGN(LambdaCallable);
};
+// Disallow OOB message handling within this scope.
+class NoOOBMessageScope : public ThreadStackResource {
+ public:
+ explicit NoOOBMessageScope(Thread* thread);
+ ~NoOOBMessageScope();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NoOOBMessageScope);
+};
+
// Fixed cache for exception handler lookup.
typedef FixedCache<intptr_t, ExceptionHandlerInfo, 16> HandlerInfoCache;
// Fixed cache for catch entry state lookup.
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 2003591..9402106 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -145,4 +145,106 @@
barrier.Exit();
}
+class IsolateTestHelper {
+ public:
+ static uword GetStackLimit(Thread* thread) { return thread->stack_limit_; }
+ static uword GetSavedStackLimit(Thread* thread) {
+ return thread->saved_stack_limit_;
+ }
+ static uword GetDeferredInterruptsMask(Thread* thread) {
+ return thread->deferred_interrupts_mask_;
+ }
+ static uword GetDeferredInterrupts(Thread* thread) {
+ return thread->deferred_interrupts_;
+ }
+};
+
+TEST_CASE(NoOOBMessageScope) {
+ // Finish any GC in progress so that no kVMInterrupt is added for GC reasons.
+ {
+ TransitionNativeToVM transition(thread);
+ GCTestHelper::CollectAllGarbage();
+ const Error& error = Error::Handle(thread->HandleInterrupts());
+ RELEASE_ASSERT(error.IsNull());
+ }
+
+ // EXPECT_EQ is picky about type agreement for its arguments.
+ const uword kZero = 0;
+ const uword kMessageInterrupt = Thread::kMessageInterrupt;
+ const uword kVMInterrupt = Thread::kVMInterrupt;
+ uword stack_limit;
+ uword interrupt_bits;
+
+ // Initially no interrupts are scheduled or deferred.
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
+
+ {
+ // Defer message interrupts.
+ NoOOBMessageScope no_msg_scope(thread);
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
+
+ // Schedule a message, it is deferred.
+ thread->ScheduleInterrupts(Thread::kMessageInterrupt);
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterrupts(thread));
+
+ // Schedule a vm interrupt, it is not deferred.
+ thread->ScheduleInterrupts(Thread::kVMInterrupt);
+ stack_limit = IsolateTestHelper::GetStackLimit(thread);
+ EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT((stack_limit & Thread::kVMInterrupt) != 0);
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterrupts(thread));
+
+ // Clear the vm interrupt. Message is still deferred.
+ interrupt_bits = thread->GetAndClearInterrupts();
+ EXPECT_EQ(kVMInterrupt, interrupt_bits);
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterrupts(thread));
+ }
+
+ // Restore message interrupts. Message is now pending.
+ stack_limit = IsolateTestHelper::GetStackLimit(thread);
+ EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT((stack_limit & Thread::kMessageInterrupt) != 0);
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
+
+ {
+ // Defer message interrupts, again. The pending interrupt is deferred.
+ NoOOBMessageScope no_msg_scope(thread);
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kMessageInterrupt,
+ IsolateTestHelper::GetDeferredInterrupts(thread));
+ }
+
+ // Restore, then clear interrupts. The world is as it was.
+ interrupt_bits = thread->GetAndClearInterrupts();
+ EXPECT_EQ(kMessageInterrupt, interrupt_bits);
+ EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
+ IsolateTestHelper::GetSavedStackLimit(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
+ EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
+}
+
} // namespace dart
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8c08ad9..7c9214a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -11162,6 +11162,7 @@
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
+ NoOOBMessageScope no_msg_scope(thread);
NoReloadScope no_reload_scope(thread);
const Function& initializer = Function::Handle(EnsureInitializerFunction());
return DartEntry::InvokeFunction(initializer, Object::empty_array());
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 45d99f9..16a1f8f 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -91,6 +91,9 @@
no_safepoint_scope_depth_(0),
#endif
reusable_handles_(),
+ defer_oob_messages_count_(0),
+ deferred_interrupts_mask_(0),
+ deferred_interrupts_(0),
stack_overflow_count_(0),
hierarchy_info_(NULL),
type_usage_info_(NULL),
@@ -395,7 +398,7 @@
MonitorLocker ml(&thread_lock_);
if (!HasScheduledInterrupts()) {
// No interrupt pending, set stack_limit_ too.
- stack_limit_.store(limit);
+ stack_limit_ = limit;
}
saved_stack_limit_ = limit;
}
@@ -405,33 +408,95 @@
}
void Thread::ScheduleInterrupts(uword interrupt_bits) {
+ MonitorLocker ml(&thread_lock_);
+ ScheduleInterruptsLocked(interrupt_bits);
+}
+
+void Thread::ScheduleInterruptsLocked(uword interrupt_bits) {
+ ASSERT(thread_lock_.IsOwnedByCurrentThread());
ASSERT((interrupt_bits & ~kInterruptsMask) == 0); // Must fit in mask.
- uword old_limit = stack_limit_.load();
- uword new_limit;
- do {
- if (old_limit == saved_stack_limit_) {
- new_limit = (kInterruptStackLimit & ~kInterruptsMask) | interrupt_bits;
- } else {
- new_limit = old_limit | interrupt_bits;
+ // Check to see if any of the requested interrupts should be deferred.
+ uword defer_bits = interrupt_bits & deferred_interrupts_mask_;
+ if (defer_bits != 0) {
+ deferred_interrupts_ |= defer_bits;
+ interrupt_bits &= ~deferred_interrupts_mask_;
+ if (interrupt_bits == 0) {
+ return;
}
- } while (!stack_limit_.compare_exchange_weak(old_limit, new_limit));
+ }
+
+ if (stack_limit_ == saved_stack_limit_) {
+ stack_limit_ = (kInterruptStackLimit & ~kInterruptsMask) | interrupt_bits;
+ } else {
+ stack_limit_ = stack_limit_ | interrupt_bits;
+ }
}
uword Thread::GetAndClearInterrupts() {
- uword interrupt_bits = 0;
- uword old_limit = stack_limit_.load();
- uword new_limit = saved_stack_limit_;
- do {
- if (old_limit == saved_stack_limit_) {
- return interrupt_bits;
- }
- interrupt_bits = interrupt_bits | (old_limit & kInterruptsMask);
- } while (!stack_limit_.compare_exchange_weak(old_limit, new_limit));
-
+ MonitorLocker ml(&thread_lock_);
+ if (stack_limit_ == saved_stack_limit_) {
+ return 0; // No interrupt was requested.
+ }
+ uword interrupt_bits = stack_limit_ & kInterruptsMask;
+ stack_limit_ = saved_stack_limit_;
return interrupt_bits;
}
+void Thread::DeferOOBMessageInterrupts() {
+ MonitorLocker ml(&thread_lock_);
+ defer_oob_messages_count_++;
+ if (defer_oob_messages_count_ > 1) {
+ // OOB message interrupts are already deferred.
+ return;
+ }
+ ASSERT(deferred_interrupts_mask_ == 0);
+ deferred_interrupts_mask_ = kMessageInterrupt;
+
+ if (stack_limit_ != saved_stack_limit_) {
+ // Defer any interrupts which are currently pending.
+ deferred_interrupts_ = stack_limit_ & deferred_interrupts_mask_;
+
+ // Clear deferrable interrupts, if present.
+ stack_limit_ = stack_limit_ & ~deferred_interrupts_mask_;
+
+ if ((stack_limit_ & kInterruptsMask) == 0) {
+ // No other pending interrupts. Restore normal stack limit.
+ stack_limit_ = saved_stack_limit_;
+ }
+ }
+#if !defined(PRODUCT)
+ if (FLAG_trace_service && FLAG_trace_service_verbose) {
+ OS::PrintErr("[+%" Pd64 "ms] Isolate %s deferring OOB interrupts\n",
+ Dart::UptimeMillis(), isolate()->name());
+ }
+#endif // !defined(PRODUCT)
+}
+
+void Thread::RestoreOOBMessageInterrupts() {
+ MonitorLocker ml(&thread_lock_);
+ defer_oob_messages_count_--;
+ if (defer_oob_messages_count_ > 0) {
+ return;
+ }
+ ASSERT(defer_oob_messages_count_ == 0);
+ ASSERT(deferred_interrupts_mask_ == kMessageInterrupt);
+ deferred_interrupts_mask_ = 0;
+ if (deferred_interrupts_ != 0) {
+ if (stack_limit_ == saved_stack_limit_) {
+ stack_limit_ = kInterruptStackLimit & ~kInterruptsMask;
+ }
+ stack_limit_ = stack_limit_ | deferred_interrupts_;
+ deferred_interrupts_ = 0;
+ }
+#if !defined(PRODUCT)
+ if (FLAG_trace_service && FLAG_trace_service_verbose) {
+ OS::PrintErr("[+%" Pd64 "ms] Isolate %s restoring OOB interrupts\n",
+ Dart::UptimeMillis(), isolate()->name());
+ }
+#endif // !defined(PRODUCT)
+}
+
ErrorPtr Thread::HandleInterrupts() {
uword interrupt_bits = GetAndClearInterrupts();
if ((interrupt_bits & kVMInterrupt) != 0) {
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 6e3ff67..2d80830 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -417,10 +417,11 @@
};
void ScheduleInterrupts(uword interrupt_bits);
+ void ScheduleInterruptsLocked(uword interrupt_bits);
ErrorPtr HandleInterrupts();
uword GetAndClearInterrupts();
bool HasScheduledInterrupts() const {
- return (stack_limit_.load() & kInterruptsMask) != 0;
+ return (stack_limit_ & kInterruptsMask) != 0;
}
// Monitor corresponding to this thread.
@@ -1030,7 +1031,7 @@
// in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
// We use only word-sized fields to avoid differences in struct packing on the
// different architectures. See also CheckOffsets in dart.cc.
- volatile RelaxedAtomic<uword> stack_limit_;
+ RelaxedAtomic<uword> stack_limit_;
uword write_barrier_mask_;
uword heap_base_;
Isolate* isolate_;
@@ -1106,6 +1107,9 @@
int32_t no_safepoint_scope_depth_;
#endif
VMHandles reusable_handles_;
+ intptr_t defer_oob_messages_count_;
+ uint16_t deferred_interrupts_mask_;
+ uint16_t deferred_interrupts_;
int32_t stack_overflow_count_;
uint32_t runtime_call_count_ = 0;
@@ -1201,6 +1205,9 @@
static void SetCurrent(Thread* current) { OSThread::SetCurrentTLS(current); }
+ void DeferOOBMessageInterrupts();
+ void RestoreOOBMessageInterrupts();
+
#define REUSABLE_FRIEND_DECLARATION(name) \
friend class Reusable##name##HandleScope;
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
@@ -1211,7 +1218,9 @@
friend class InterruptChecker;
friend class Isolate;
friend class IsolateGroup;
+ friend class IsolateTestHelper;
friend class NoActiveIsolateScope;
+ friend class NoOOBMessageScope;
friend class NoReloadScope;
friend class Simulator;
friend class StackZone;
diff --git a/tests/lib/isolate/kill_infinite_loop_in_initializer_test.dart b/tests/lib/isolate/kill_infinite_loop_in_initializer_test.dart
deleted file mode 100644
index 321fbda4..0000000
--- a/tests/lib/isolate/kill_infinite_loop_in_initializer_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-// VMOptions=--enable-isolate-groups --experimental-enable-isolate-groups-jit
-// VMOptions=--no-enable-isolate-groups
-
-// Regression test against out-of-band messages being blocked during lazy
-// static field initialization.
-
-import "dart:isolate";
-import "dart:async";
-import "package:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
-
-dynamic staticFieldWithBadInitializer = badInitializer();
-
-badInitializer() {
- print("badInitializer");
- for (;;) {}
- return 42; // Unreachable.
-}
-
-child(message) {
- print("child");
- RawReceivePort port = new RawReceivePort();
- print(staticFieldWithBadInitializer);
- port.close(); // Unreachable.
-}
-
-void main() {
- asyncStart();
- Isolate.spawn(child, null).then((Isolate isolate) {
- print("spawned");
- late RawReceivePort exitSignal;
- exitSignal = new RawReceivePort((_) {
- print("onExit");
- exitSignal.close();
- asyncEnd();
- });
- isolate.addOnExitListener(exitSignal.sendPort);
- isolate.kill(priority: Isolate.immediate);
- });
-}
diff --git a/tests/lib_2/isolate/kill_infinite_loop_in_initializer_test.dart b/tests/lib_2/isolate/kill_infinite_loop_in_initializer_test.dart
deleted file mode 100644
index af8650e..0000000
--- a/tests/lib_2/isolate/kill_infinite_loop_in_initializer_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-// VMOptions=--enable-isolate-groups --experimental-enable-isolate-groups-jit
-// VMOptions=--no-enable-isolate-groups
-
-// Regression test against out-of-band messages being blocked during lazy
-// static field initialization.
-
-import "dart:isolate";
-import "dart:async";
-import "package:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
-
-dynamic staticFieldWithBadInitializer = badInitializer();
-
-badInitializer() {
- print("badInitializer");
- for (;;) {}
- return 42; // Unreachable.
-}
-
-child(message) {
- print("child");
- RawReceivePort port = new RawReceivePort();
- print(staticFieldWithBadInitializer);
- port.close(); // Unreachable.
-}
-
-void main() {
- asyncStart();
- Isolate.spawn(child, null).then((Isolate isolate) {
- print("spawned");
- RawReceivePort exitSignal;
- exitSignal = new RawReceivePort((_) {
- print("onExit");
- exitSignal.close();
- asyncEnd();
- });
- isolate.addOnExitListener(exitSignal.sendPort);
- isolate.kill(priority: Isolate.immediate);
- });
-}
diff --git a/tools/VERSION b/tools/VERSION
index 67f5806..f7ef7a9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 309
+PRERELEASE 310
PRERELEASE_PATCH 0
\ No newline at end of file