mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:37:53 +00:00
When reordering constructor initializers, use correct types for temp vars.
In strong mode, when a call to a super-initializer is reordered, we can use the static type of the super-initializer arguments to set the types of the temporary variables that we use to do the reordering. This is desirable because it might help avoid unnecessary casts. In non-strong mode, we use `dynamic` for the temporary variables, to replicate Dart 1.0 behavior. R=scheglov@google.com Review-Url: https://codereview.chromium.org/2993193002 .
This commit is contained in:
parent
107335c1d0
commit
41170b0a15
|
@ -511,7 +511,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
initializer = buildFieldInitializer(true, formal.name,
|
||||
formal.charOffset, new VariableGet(formal.declaration));
|
||||
}
|
||||
member.addInitializer(initializer);
|
||||
member.addInitializer(initializer, _typeInferrer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
}
|
||||
_typeInferrer.inferInitializer(initializer);
|
||||
if (member is KernelConstructorBuilder && !member.isExternal) {
|
||||
member.addInitializer(initializer);
|
||||
member.addInitializer(initializer, _typeInferrer);
|
||||
} else {
|
||||
deprecated_addCompileTimeError(
|
||||
token.charOffset, "Can't have initializers: ${member.name}");
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
library fasta.kernel_procedure_builder;
|
||||
|
||||
import 'package:front_end/src/fasta/type_inference/type_inferrer.dart'
|
||||
show TypeInferrer;
|
||||
|
||||
import 'package:kernel/ast.dart'
|
||||
show
|
||||
Arguments,
|
||||
|
@ -389,7 +392,7 @@ class KernelConstructorBuilder extends KernelFunctionBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
void addInitializer(Initializer initializer) {
|
||||
void addInitializer(Initializer initializer, TypeInferrer typeInferrer) {
|
||||
List<Initializer> initializers = constructor.initializers;
|
||||
if (initializer is SuperInitializer) {
|
||||
checkSuperOrThisInitializer(initializer);
|
||||
|
@ -420,8 +423,13 @@ class KernelConstructorBuilder extends KernelFunctionBuilder {
|
|||
Arguments arguments = superInitializer.arguments;
|
||||
List<Expression> positional = arguments.positional;
|
||||
for (int i = 0; i < positional.length; i++) {
|
||||
VariableDeclaration variable =
|
||||
new VariableDeclaration.forValue(positional[i], isFinal: true);
|
||||
var type = typeInferrer.typeSchemaEnvironment.strongMode
|
||||
? positional[i].getStaticType(typeInferrer.typeSchemaEnvironment)
|
||||
: const DynamicType();
|
||||
VariableDeclaration variable = new VariableDeclaration.forValue(
|
||||
positional[i],
|
||||
isFinal: true,
|
||||
type: type);
|
||||
initializers
|
||||
.add(new LocalInitializer(variable)..parent = constructor);
|
||||
positional[i] = new VariableGet(variable)..parent = arguments;
|
||||
|
|
|
@ -2111,6 +2111,10 @@ class KernelTypeInferenceEngine extends TypeInferenceEngineImpl {
|
|||
return accessorNode;
|
||||
}
|
||||
|
||||
@override
|
||||
TypeInferrer createDisabledTypeInferrer() =>
|
||||
new TypeInferrerDisabled(typeSchemaEnvironment);
|
||||
|
||||
@override
|
||||
KernelTypeInferrer createLocalTypeInferrer(
|
||||
Uri uri, TypeInferenceListener listener, InterfaceType thisType) {
|
||||
|
|
|
@ -36,8 +36,6 @@ import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
|
|||
import '../type_inference/type_inference_listener.dart'
|
||||
show TypeInferenceListener;
|
||||
|
||||
import '../type_inference/type_inferrer.dart' show TypeInferrerDisabled;
|
||||
|
||||
import '../util/link.dart' show Link;
|
||||
|
||||
import 'source_library_builder.dart' show SourceLibraryBuilder;
|
||||
|
@ -434,7 +432,7 @@ class DietListener extends StackListener {
|
|||
thisType = cls.thisType;
|
||||
}
|
||||
var typeInferrer = library.disableTypeInference
|
||||
? new TypeInferrerDisabled()
|
||||
? typeInferenceEngine.createDisabledTypeInferrer()
|
||||
: typeInferenceEngine.createLocalTypeInferrer(uri, listener, thisType);
|
||||
return new BodyBuilder(library, builder, memberScope, formalParameterScope,
|
||||
hierarchy, coreTypes, currentClass, isInstanceMember, uri, typeInferrer)
|
||||
|
|
|
@ -140,6 +140,10 @@ abstract class TypeInferenceEngine {
|
|||
TypeInferrer createLocalTypeInferrer(
|
||||
Uri uri, TypeInferenceListener listener, InterfaceType thisType);
|
||||
|
||||
/// Creates a disabled type inferrer (intended for debugging and profiling
|
||||
/// only).
|
||||
TypeInferrer createDisabledTypeInferrer();
|
||||
|
||||
/// Creates a [TypeInferrer] object which is ready to perform type inference
|
||||
/// on the given [field].
|
||||
TypeInferrer createTopLevelTypeInferrer(TypeInferenceListener listener,
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
// BSD-style license that can be found in the LICENSE.md file.
|
||||
|
||||
import 'package:front_end/src/base/instrumentation.dart';
|
||||
import 'package:front_end/src/fasta/problems.dart' show unhandled;
|
||||
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
|
||||
import 'package:front_end/src/fasta/names.dart' show callName;
|
||||
import 'package:front_end/src/fasta/problems.dart' show unhandled;
|
||||
import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
|
||||
import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
|
||||
import 'package:front_end/src/fasta/type_inference/type_promotion.dart';
|
||||
|
@ -203,6 +203,9 @@ abstract class TypeInferrer {
|
|||
/// this method body or initializer.
|
||||
TypePromoter get typePromoter;
|
||||
|
||||
/// Gets the [TypeSchemaEnvironment] being used for type inference.
|
||||
TypeSchemaEnvironment get typeSchemaEnvironment;
|
||||
|
||||
/// The URI of the code for which type inference is currently being
|
||||
/// performed--this is used for testing.
|
||||
String get uri;
|
||||
|
@ -233,6 +236,11 @@ class TypeInferrerDisabled extends TypeInferrer {
|
|||
@override
|
||||
final typePromoter = new TypePromoterDisabled();
|
||||
|
||||
@override
|
||||
final TypeSchemaEnvironment typeSchemaEnvironment;
|
||||
|
||||
TypeInferrerDisabled(this.typeSchemaEnvironment);
|
||||
|
||||
@override
|
||||
String get uri => null;
|
||||
|
||||
|
|
|
@ -427,6 +427,7 @@ regress/issue_29981: Crash
|
|||
regress/issue_29984: Crash
|
||||
regress/issue_29985: Crash
|
||||
regress/issue_29987: Crash
|
||||
reorder_super: Crash
|
||||
static_setter: Crash
|
||||
store_load: Crash
|
||||
stringliteral: Crash
|
||||
|
|
39
pkg/front_end/testcases/reorder_super.dart
Normal file
39
pkg/front_end/testcases/reorder_super.dart
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
// This test verifies that super calls get reordered properly. It exercises the
|
||||
// case where the arguments to super have a type other than `dynamic`.
|
||||
String events = '';
|
||||
|
||||
int f(x) {
|
||||
events += 'f($x)\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
String g(x) {
|
||||
events += 'g($x)\n';
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
class B {
|
||||
num x;
|
||||
String y;
|
||||
B(this.x, this.y) {
|
||||
events += 'super($x, $y)\n';
|
||||
}
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
final z;
|
||||
C()
|
||||
: super(f(1), g(2)),
|
||||
z = f(3);
|
||||
}
|
||||
|
||||
main() {
|
||||
new C();
|
||||
if (events != 'f(1)\ng(2)\nf(3)\nsuper(0, foo)\n') {
|
||||
throw 'Unexpected sequence of events: $events';
|
||||
}
|
||||
}
|
33
pkg/front_end/testcases/reorder_super.dart.direct.expect
Normal file
33
pkg/front_end/testcases/reorder_super.dart.direct.expect
Normal file
|
@ -0,0 +1,33 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class B extends core::Object {
|
||||
field core::num x;
|
||||
field core::String y;
|
||||
constructor •(core::num x, core::String y) → void
|
||||
: self::B::x = x, self::B::y = y, super core::Object::•() {
|
||||
self::events = self::events.+("super(${this.x}, ${this.y})\n");
|
||||
}
|
||||
}
|
||||
class C extends self::B {
|
||||
final field dynamic z;
|
||||
constructor •() → void
|
||||
: final dynamic #t1 = self::f(1), final dynamic #t2 = self::g(2), self::C::z = self::f(3), super self::B::•(#t1, #t2)
|
||||
;
|
||||
}
|
||||
static field core::String events = "";
|
||||
static method f(dynamic x) → core::int {
|
||||
self::events = self::events.+("f(${x})\n");
|
||||
return 0;
|
||||
}
|
||||
static method g(dynamic x) → core::String {
|
||||
self::events = self::events.+("g(${x})\n");
|
||||
return "foo";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
new self::C::•();
|
||||
if(!self::events.==("f(1)\ng(2)\nf(3)\nsuper(0, foo)\n")) {
|
||||
throw "Unexpected sequence of events: ${self::events}";
|
||||
}
|
||||
}
|
22
pkg/front_end/testcases/reorder_super.dart.outline.expect
Normal file
22
pkg/front_end/testcases/reorder_super.dart.outline.expect
Normal file
|
@ -0,0 +1,22 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class B extends core::Object {
|
||||
field core::num x;
|
||||
field core::String y;
|
||||
constructor •(core::num x, core::String y) → void
|
||||
;
|
||||
}
|
||||
class C extends self::B {
|
||||
final field dynamic z;
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
static field core::String events;
|
||||
static method f(dynamic x) → core::int
|
||||
;
|
||||
static method g(dynamic x) → core::String
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
33
pkg/front_end/testcases/reorder_super.dart.strong.expect
Normal file
33
pkg/front_end/testcases/reorder_super.dart.strong.expect
Normal file
|
@ -0,0 +1,33 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class B extends core::Object {
|
||||
field core::num x;
|
||||
field core::String y;
|
||||
constructor •(core::num x, core::String y) → void
|
||||
: self::B::x = x, self::B::y = y, super core::Object::•() {
|
||||
self::events = self::events.{core::String::+}("super(${this.{self::B::x}}, ${this.{self::B::y}})\n");
|
||||
}
|
||||
}
|
||||
class C extends self::B {
|
||||
final field dynamic z;
|
||||
constructor •() → void
|
||||
: final core::int #t1 = self::f(1), final core::String #t2 = self::g(2), self::C::z = self::f(3), super self::B::•(#t1, #t2)
|
||||
;
|
||||
}
|
||||
static field core::String events = "";
|
||||
static method f(dynamic x) → core::int {
|
||||
self::events = self::events.{core::String::+}("f(${x})\n");
|
||||
return 0;
|
||||
}
|
||||
static method g(dynamic x) → core::String {
|
||||
self::events = self::events.{core::String::+}("g(${x})\n");
|
||||
return "foo";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
new self::C::•();
|
||||
if(!self::events.{core::String::==}("f(1)\ng(2)\nf(3)\nsuper(0, foo)\n")) {
|
||||
throw "Unexpected sequence of events: ${self::events}";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue