mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[cfe] Add explicit type argument to .map(...).toList()
Expressions like List<VariableDeclaration> variables = ... List<Expression> reads = variables.map((v) => VariableGet(v)).toList() don't get the intended type argument `<Expression>` through inference, but instead the type inferred from the return type of the closure, in this case `<VariableGet>`. This causes problems when used with the AST which assumes that expressions are interchangeable wherever they are used, and is likely the cause of https://github.com/flutter/flutter/issues/102077 . This CL adds an explicit type argument in these cases. TEST=general/infer_map Change-Id: I0bcae21f06c54f290dc20686b0d84c065d8ea04c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241605 Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
35c78ac66b
commit
f26c0e2056
12 changed files with 192 additions and 10 deletions
|
@ -179,7 +179,7 @@ class JsUtilOptimizer extends Transformer {
|
|||
StringLiteral(_getExtensionMemberName(node)),
|
||||
ListLiteral(function.positionalParameters
|
||||
.sublist(1)
|
||||
.map((argument) => VariableGet(argument))
|
||||
.map<Expression>((argument) => VariableGet(argument))
|
||||
.toList())
|
||||
], types: [
|
||||
function.returnType
|
||||
|
@ -294,8 +294,8 @@ class JsUtilOptimizer extends Transformer {
|
|||
}
|
||||
|
||||
// Lower arguments in other kinds of Lists.
|
||||
var callUncheckedArguments;
|
||||
var entryType;
|
||||
List<Expression> callUncheckedArguments;
|
||||
DartType entryType;
|
||||
if (argumentsList is ListLiteral) {
|
||||
if (argumentsList.expressions.length >= callUncheckedTargets.length) {
|
||||
return node;
|
||||
|
@ -309,7 +309,7 @@ class JsUtilOptimizer extends Transformer {
|
|||
return node;
|
||||
}
|
||||
callUncheckedArguments = argumentsListConstant.entries
|
||||
.map((constant) => ConstantExpression(
|
||||
.map<Expression>((constant) => ConstantExpression(
|
||||
constant, constant.getType(_staticTypeContext)))
|
||||
.toList();
|
||||
entryType = argumentsListConstant.typeArgument;
|
||||
|
|
|
@ -191,8 +191,9 @@ class Dart2jsTarget extends Target {
|
|||
.getTopLevelProcedure('dart:core', '_createInvocationMirror'),
|
||||
ir.Arguments(<ir.Expression>[
|
||||
ir.StringLiteral(name)..fileOffset = offset,
|
||||
ir.ListLiteral(
|
||||
arguments.types.map((t) => ir.TypeLiteral(t)).toList()),
|
||||
ir.ListLiteral(arguments.types
|
||||
.map<ir.Expression>((t) => ir.TypeLiteral(t))
|
||||
.toList()),
|
||||
ir.ListLiteral(arguments.positional)..fileOffset = offset,
|
||||
ir.MapLiteral(List<ir.MapLiteralEntry>.from(
|
||||
arguments.named.map((ir.NamedExpression arg) {
|
||||
|
|
|
@ -92,7 +92,7 @@ class RedirectingFactoryBody extends ReturnStatement {
|
|||
static Expression _makeForwardingCall(
|
||||
Member target, List<DartType> typeArguments, FunctionNode function) {
|
||||
final List<Expression> positional = function.positionalParameters
|
||||
.map((v) => new VariableGet(v)..fileOffset = v.fileOffset)
|
||||
.map<Expression>((v) => new VariableGet(v)..fileOffset = v.fileOffset)
|
||||
.toList();
|
||||
final List<NamedExpression> named = function.namedParameters
|
||||
.map((v) => new NamedExpression(
|
||||
|
|
34
pkg/front_end/testcases/general/infer_map.dart
Normal file
34
pkg/front_end/testcases/general/infer_map.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
class A {}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
List<int> intList = [1, 2];
|
||||
|
||||
List<A> list1 = intList.map((i) => new B()).toList();
|
||||
|
||||
test(List<A> list) {
|
||||
try {
|
||||
list.add(new A());
|
||||
list.removeLast();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
throw 'Expected subtype error';
|
||||
}
|
||||
|
||||
main() {
|
||||
test(list1);
|
||||
list1 = intList.map((i) => new B()).toList();
|
||||
test(list1);
|
||||
|
||||
List<A> list2 = intList.map((i) => new B()).toList();
|
||||
test(list2);
|
||||
list2 = intList.map((i) => new B()).toList();
|
||||
test(list2);
|
||||
|
||||
test(intList.map((i) => new B()).toList());
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
class A {}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
List<int> intList = [1, 2];
|
||||
List<A> list1 = intList.map((i) => new B()).toList();
|
||||
test(List<A> list) {}
|
||||
main() {}
|
|
@ -0,0 +1,9 @@
|
|||
List<A> list1 = intList.map((i) => new B()).toList();
|
||||
List<int> intList = [1, 2];
|
||||
|
||||
class A {}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
main() {}
|
||||
test(List<A> list) {}
|
36
pkg/front_end/testcases/general/infer_map.dart.weak.expect
Normal file
36
pkg/front_end/testcases/general/infer_map.dart.weak.expect
Normal file
|
@ -0,0 +1,36 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
synthetic constructor •() → self::A
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class B extends self::A {
|
||||
synthetic constructor •() → self::B
|
||||
: super self::A::•()
|
||||
;
|
||||
}
|
||||
static field core::List<core::int> intList = <core::int>[1, 2];
|
||||
static field core::List<self::A> list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
static method test(core::List<self::A> list) → dynamic {
|
||||
try {
|
||||
list.{core::List::add}(new self::A::•()){(self::A) → void};
|
||||
list.{core::List::removeLast}(){() → self::A};
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
return;
|
||||
}
|
||||
throw "Expected subtype error";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::test(self::list1);
|
||||
self::list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(self::list1);
|
||||
core::List<self::A> list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
self::test(self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>});
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
synthetic constructor •() → self::A
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class B extends self::A {
|
||||
synthetic constructor •() → self::B
|
||||
: super self::A::•()
|
||||
;
|
||||
}
|
||||
static field core::List<core::int> intList = <core::int>[1, 2];
|
||||
static field core::List<self::A> list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
static method test(core::List<self::A> list) → dynamic {
|
||||
try {
|
||||
list.{core::List::add}(new self::A::•()){(self::A) → void};
|
||||
list.{core::List::removeLast}(){() → self::A};
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
return;
|
||||
}
|
||||
throw "Expected subtype error";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::test(self::list1);
|
||||
self::list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(self::list1);
|
||||
core::List<self::A> list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
self::test(self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>});
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
synthetic constructor •() → self::A
|
||||
;
|
||||
}
|
||||
class B extends self::A {
|
||||
synthetic constructor •() → self::B
|
||||
;
|
||||
}
|
||||
static field core::List<core::int> intList;
|
||||
static field core::List<self::A> list1;
|
||||
static method test(core::List<self::A> list) → dynamic
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,36 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
synthetic constructor •() → self::A
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class B extends self::A {
|
||||
synthetic constructor •() → self::B
|
||||
: super self::A::•()
|
||||
;
|
||||
}
|
||||
static field core::List<core::int> intList = core::_GrowableList::_literal2<core::int>(1, 2);
|
||||
static field core::List<self::A> list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
static method test(core::List<self::A> list) → dynamic {
|
||||
try {
|
||||
list.{core::List::add}(new self::A::•()){(self::A) → void};
|
||||
list.{core::List::removeLast}(){() → self::A};
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
return;
|
||||
}
|
||||
throw "Expected subtype error";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::test(self::list1);
|
||||
self::list1 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(self::list1);
|
||||
core::List<self::A> list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
list2 = self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>};
|
||||
self::test(list2);
|
||||
self::test(self::intList.{core::Iterable::map}<self::B>((core::int i) → self::B => new self::B::•()){((core::int) → self::B) → core::Iterable<self::B>}.{core::Iterable::toList}(){({growable: core::bool}) → core::List<self::B>});
|
||||
}
|
|
@ -141,8 +141,10 @@ void addConstructor(
|
|||
..parent = syntheticConstructor)
|
||||
.toList();
|
||||
|
||||
initializersConstructor.add(SuperInitializer(superConstructor,
|
||||
Arguments(superParameters.map((f) => VariableGet(f)).toList()))
|
||||
initializersConstructor.add(SuperInitializer(
|
||||
superConstructor,
|
||||
Arguments(
|
||||
superParameters.map<Expression>((f) => VariableGet(f)).toList()))
|
||||
..parent = syntheticConstructor);
|
||||
|
||||
syntheticConstructor.function.namedParameters
|
||||
|
|
|
@ -231,7 +231,9 @@ class VmTarget extends Target {
|
|||
_fixedLengthList(
|
||||
coreTypes,
|
||||
coreTypes.typeLegacyRawType,
|
||||
arguments.types.map((t) => new TypeLiteral(t)).toList(),
|
||||
arguments.types
|
||||
.map<Expression>((t) => new TypeLiteral(t))
|
||||
.toList(),
|
||||
arguments.fileOffset),
|
||||
_fixedLengthList(coreTypes, const DynamicType(), arguments.positional,
|
||||
arguments.fileOffset),
|
||||
|
|
Loading…
Reference in a new issue