mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:07:49 +00:00
Implement type inference for try/catch blocks.
Note that the types of the exception and stack trace variables are set in the BodyBuilder since they do not depend on inference of other parts of the function. R=scheglov@google.com Review-Url: https://codereview.chromium.org/2954823002 .
This commit is contained in:
parent
b94fdceadc
commit
7553b2e75c
|
@ -1940,9 +1940,11 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
if (catchParameters != null) {
|
||||
if (catchParameters.required.length > 0) {
|
||||
exception = catchParameters.required[0];
|
||||
exception.type = type;
|
||||
}
|
||||
if (catchParameters.required.length > 1) {
|
||||
stackTrace = catchParameters.required[1];
|
||||
stackTrace.type = coreTypes.stackTraceClass.rawType;
|
||||
}
|
||||
if (catchParameters.required.length > 2 ||
|
||||
catchParameters.optional != null) {
|
||||
|
@ -1962,10 +1964,10 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
|||
Statement tryBlock = popStatement();
|
||||
if (compileTimeErrorInTry == null) {
|
||||
if (catches != null) {
|
||||
tryBlock = new TryCatch(tryBlock, catches);
|
||||
tryBlock = new KernelTryCatch(tryBlock, catches);
|
||||
}
|
||||
if (finallyBlock != null) {
|
||||
tryBlock = new TryFinally(tryBlock, finallyBlock);
|
||||
tryBlock = new KernelTryFinally(tryBlock, finallyBlock);
|
||||
}
|
||||
push(tryBlock);
|
||||
} else {
|
||||
|
|
|
@ -1874,6 +1874,35 @@ class KernelThrow extends Throw implements KernelExpression {
|
|||
}
|
||||
}
|
||||
|
||||
/// Concrete shadow object representing a try-catch block in kernel form.
|
||||
class KernelTryCatch extends TryCatch implements KernelStatement {
|
||||
KernelTryCatch(Statement body, List<Catch> catches) : super(body, catches);
|
||||
|
||||
@override
|
||||
void _inferStatement(KernelTypeInferrer inferrer) {
|
||||
inferrer.listener.tryCatchEnter(this);
|
||||
inferrer.inferStatement(body);
|
||||
for (var catch_ in catches) {
|
||||
inferrer.inferStatement(catch_.body);
|
||||
}
|
||||
inferrer.listener.tryCatchExit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete shadow object representing a try-finally block in kernel form.
|
||||
class KernelTryFinally extends TryFinally implements KernelStatement {
|
||||
KernelTryFinally(Statement body, Statement finalizer)
|
||||
: super(body, finalizer);
|
||||
|
||||
@override
|
||||
void _inferStatement(KernelTypeInferrer inferrer) {
|
||||
inferrer.listener.tryFinallyEnter(this);
|
||||
inferrer.inferStatement(body);
|
||||
inferrer.inferStatement(finalizer);
|
||||
inferrer.listener.tryFinallyExit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete implementation of [TypeInferenceEngine] specialized to work with
|
||||
/// kernel objects.
|
||||
class KernelTypeInferenceEngine extends TypeInferenceEngineImpl {
|
||||
|
|
|
@ -334,6 +334,18 @@ class TypeInferenceListener
|
|||
void throwExit(Throw expression, DartType inferredType) =>
|
||||
debugExpressionExit('throw', expression, inferredType);
|
||||
|
||||
void tryCatchEnter(TryCatch statement) =>
|
||||
debugStatementEnter('tryCatch', statement);
|
||||
|
||||
void tryCatchExit(TryCatch statement) =>
|
||||
debugStatementExit('tryCatch', statement);
|
||||
|
||||
void tryFinallyEnter(TryFinally statement) =>
|
||||
debugStatementEnter('tryFinally', statement);
|
||||
|
||||
void tryFinallyExit(TryFinally statement) =>
|
||||
debugStatementExit('tryFinally', statement);
|
||||
|
||||
bool variableAssignEnter(Expression expression, DartType typeContext) =>
|
||||
debugExpressionEnter("variableAssign", expression, typeContext);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class C extends core::Object {
|
|||
core::print(this.onlySetter);
|
||||
throw "No error thrown";
|
||||
}
|
||||
on core::NoSuchMethodError catch(final dynamic e) {
|
||||
on core::NoSuchMethodError catch(final core::NoSuchMethodError e) {
|
||||
core::print("Expected error: ${e}");
|
||||
}
|
||||
this.onlySetter = "hest";
|
||||
|
@ -42,7 +42,7 @@ static method main() → dynamic {
|
|||
core::print(throw new core::NoSuchMethodError::_withType(null, #onlySetter, 33, <dynamic>[].toList(growable: false), <dynamic, dynamic>{}, null));
|
||||
throw "No error thrown";
|
||||
}
|
||||
on core::NoSuchMethodError catch(final dynamic e) {
|
||||
on core::NoSuchMethodError catch(final core::NoSuchMethodError e) {
|
||||
core::print("Expected error: ${e}");
|
||||
}
|
||||
self::onlySetter = "fisk";
|
||||
|
|
|
@ -21,7 +21,7 @@ static method main() → dynamic {
|
|||
try {
|
||||
throw "fisk";
|
||||
}
|
||||
on core::String catch(final dynamic e, final dynamic s) {
|
||||
on core::String catch(final core::String e, final core::StackTrace s) {
|
||||
core::print(e);
|
||||
if(!s.==(null))
|
||||
core::print(s);
|
||||
|
@ -72,7 +72,7 @@ static method main() → dynamic {
|
|||
core::print(throw new core::NoSuchMethodError::_withType(null, #toString, 32, <dynamic>[].toList(growable: false), <dynamic, dynamic>{}, null));
|
||||
throw "Shouldn't work";
|
||||
}
|
||||
on core::NoSuchMethodError catch(final dynamic e) {
|
||||
on core::NoSuchMethodError catch(final core::NoSuchMethodError e) {
|
||||
core::print("As expected: ${e}");
|
||||
}
|
||||
core::print(core::int::parse("42"));
|
||||
|
|
31
pkg/front_end/testcases/inference/try_catch.dart
Normal file
31
pkg/front_end/testcases/inference/try_catch.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
class C {}
|
||||
|
||||
class D {}
|
||||
|
||||
class E {}
|
||||
|
||||
void test(void f()) {
|
||||
try {
|
||||
var /*@type=int*/ x = 0;
|
||||
f();
|
||||
} on C {
|
||||
var /*@type=int*/ x = 0;
|
||||
} on D catch (x) {
|
||||
var /*@type=D*/ x2 = x;
|
||||
} on E catch (x, y) {
|
||||
var /*@type=E*/ x2 = x;
|
||||
var /*@type=StackTrace*/ y2 = y;
|
||||
} catch (x, y) {
|
||||
var /*@type=dynamic*/ x2 = x;
|
||||
var /*@type=StackTrace*/ y2 = y;
|
||||
}
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,40 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
dynamic x = 0;
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(no-exception-var) {
|
||||
dynamic x = 0;
|
||||
}
|
||||
on self::D catch(final self::D x) {
|
||||
dynamic x2 = x;
|
||||
}
|
||||
on self::E catch(final self::E x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
dynamic y2 = y;
|
||||
}
|
||||
on dynamic catch(final dynamic x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
dynamic y2 = y;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,40 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
core::int x = 0;
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(no-exception-var) {
|
||||
core::int x = 0;
|
||||
}
|
||||
on self::D catch(final self::D x) {
|
||||
self::D x2 = x;
|
||||
}
|
||||
on self::E catch(final self::E x, final core::StackTrace y) {
|
||||
self::E x2 = x;
|
||||
core::StackTrace y2 = y;
|
||||
}
|
||||
on dynamic catch(final dynamic x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
core::StackTrace y2 = y;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
33
pkg/front_end/testcases/inference/try_catch_finally.dart
Normal file
33
pkg/front_end/testcases/inference/try_catch_finally.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
class C {}
|
||||
|
||||
class D {}
|
||||
|
||||
class E {}
|
||||
|
||||
void test(void f()) {
|
||||
try {
|
||||
var /*@type=int*/ x = 0;
|
||||
f();
|
||||
} on C {
|
||||
var /*@type=int*/ x = 0;
|
||||
} on D catch (x) {
|
||||
var /*@type=D*/ x2 = x;
|
||||
} on E catch (x, y) {
|
||||
var /*@type=E*/ x2 = x;
|
||||
var /*@type=StackTrace*/ y2 = y;
|
||||
} catch (x, y) {
|
||||
var /*@type=dynamic*/ x2 = x;
|
||||
var /*@type=StackTrace*/ y2 = y;
|
||||
} finally {
|
||||
var /*@type=int*/ x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,44 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try
|
||||
try {
|
||||
dynamic x = 0;
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(no-exception-var) {
|
||||
dynamic x = 0;
|
||||
}
|
||||
on self::D catch(final self::D x) {
|
||||
dynamic x2 = x;
|
||||
}
|
||||
on self::E catch(final self::E x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
dynamic y2 = y;
|
||||
}
|
||||
on dynamic catch(final dynamic x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
dynamic y2 = y;
|
||||
}
|
||||
finally {
|
||||
dynamic x = 0;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,44 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class E extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try
|
||||
try {
|
||||
core::int x = 0;
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(no-exception-var) {
|
||||
core::int x = 0;
|
||||
}
|
||||
on self::D catch(final self::D x) {
|
||||
self::D x2 = x;
|
||||
}
|
||||
on self::E catch(final self::E x, final core::StackTrace y) {
|
||||
self::E x2 = x;
|
||||
core::StackTrace y2 = y;
|
||||
}
|
||||
on dynamic catch(final dynamic x, final core::StackTrace y) {
|
||||
dynamic x2 = x;
|
||||
core::StackTrace y2 = y;
|
||||
}
|
||||
finally {
|
||||
core::int x = 0;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
29
pkg/front_end/testcases/inference/try_catch_promotion.dart
Normal file
29
pkg/front_end/testcases/inference/try_catch_promotion.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
class C {}
|
||||
|
||||
class D extends C {}
|
||||
|
||||
class E extends StackTrace {}
|
||||
|
||||
void test(void f()) {
|
||||
try {
|
||||
f();
|
||||
} on C catch (x, y) {
|
||||
var /*@type=C*/ x1 = x;
|
||||
var /*@type=StackTrace*/ y1 = y;
|
||||
if (x is D) {
|
||||
var /*@type=D*/ x2 = /*@promotedType=D*/ x;
|
||||
}
|
||||
if (y is E) {
|
||||
var /*@type=E*/ y2 = /*@promotedType=E*/ y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,35 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
}
|
||||
class E extends core::StackTrace {
|
||||
constructor •() → void
|
||||
: super core::StackTrace::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(final self::C x, final core::StackTrace y) {
|
||||
dynamic x1 = x;
|
||||
dynamic y1 = y;
|
||||
if(x is self::D) {
|
||||
dynamic x2 = x{self::D};
|
||||
}
|
||||
if(y is self::E) {
|
||||
dynamic y2 = y{self::E};
|
||||
}
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,20 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
class E extends core::StackTrace {
|
||||
constructor •() → void
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,35 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class C extends core::Object {
|
||||
constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
}
|
||||
class D extends self::C {
|
||||
constructor •() → void
|
||||
: super self::C::•()
|
||||
;
|
||||
}
|
||||
class E extends core::StackTrace {
|
||||
constructor •() → void
|
||||
: super core::StackTrace::•()
|
||||
;
|
||||
}
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
f.call();
|
||||
}
|
||||
on self::C catch(final self::C x, final core::StackTrace y) {
|
||||
self::C x1 = x;
|
||||
core::StackTrace y1 = y;
|
||||
if(x is self::D) {
|
||||
self::D x2 = x{self::D};
|
||||
}
|
||||
if(y is self::E) {
|
||||
self::E y2 = y{self::E};
|
||||
}
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
17
pkg/front_end/testcases/inference/try_finally.dart
Normal file
17
pkg/front_end/testcases/inference/try_finally.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
// 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
void test(void f()) {
|
||||
try {
|
||||
var /*@type=int*/ x = 0;
|
||||
f();
|
||||
} finally {
|
||||
var /*@type=int*/ x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,13 @@
|
|||
library test;
|
||||
import self as self;
|
||||
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
dynamic x = 0;
|
||||
f.call();
|
||||
}
|
||||
finally {
|
||||
dynamic x = 0;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,7 @@
|
|||
library test;
|
||||
import self as self;
|
||||
|
||||
static method test(() → void f) → void
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,14 @@
|
|||
library test;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method test(() → void f) → void {
|
||||
try {
|
||||
core::int x = 0;
|
||||
f.call();
|
||||
}
|
||||
finally {
|
||||
core::int x = 0;
|
||||
}
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -362,6 +362,10 @@ inference/subexpressions_of_explicitly_typed_fields: Crash
|
|||
inference/this_reference: Crash
|
||||
inference/top_level_return_and_yield: Crash
|
||||
inference/toplevel_inference_toplevel_var: Crash
|
||||
inference/try_catch: Crash
|
||||
inference/try_catch_finally: Crash
|
||||
inference/try_catch_promotion: Crash
|
||||
inference/try_finally: Crash
|
||||
inference/type_cast: Crash
|
||||
inference/type_promotion_ignores_local_functions: Crash
|
||||
inference/type_promotion_not_and_not: Crash
|
||||
|
|
|
@ -71,6 +71,7 @@ class CoreTypes {
|
|||
|
||||
Library _asyncLibrary;
|
||||
Class _futureClass;
|
||||
Class _stackTraceClass;
|
||||
Class _streamClass;
|
||||
Class _completerClass;
|
||||
Class _futureOrClass;
|
||||
|
@ -235,6 +236,10 @@ class CoreTypes {
|
|||
return _printProcedure ??= _index.getTopLevelMember('dart:core', 'print');
|
||||
}
|
||||
|
||||
Class get stackTraceClass {
|
||||
return _stackTraceClass ??= _index.getClass('dart:core', 'StackTrace');
|
||||
}
|
||||
|
||||
Class get streamClass {
|
||||
return _streamClass ??= _index.getClass('dart:async', 'Stream');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue