From dd0a00f581f1416b2628970d528b5d76e1957f00 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Thu, 22 Jun 2017 12:17:08 -0700 Subject: [PATCH] Infer the return types of local functions where appropriate. Note that we do this in order to be consistent with type inference of function expressions. See https://codereview.chromium.org/2209293002. R=sigmund@google.com Review-Url: https://codereview.chromium.org/2950213002 . --- .../task/strong/front_end_inference_test.dart | 24 +++ .../lib/src/fasta/kernel/body_builder.dart | 6 +- .../src/fasta/kernel/kernel_shadow_ast.dart | 162 ++---------------- .../fasta/type_inference/type_inferrer.dart | 133 ++++++++++++++ pkg/front_end/test/fasta/kompile.status | 1 + pkg/front_end/test/fasta/strong.status | 1 - ...unction_referenced_before_declaration.dart | 20 +++ ...nced_before_declaration.dart.direct.expect | 12 ++ ...ced_before_declaration.dart.outline.expect | 7 + ...nced_before_declaration.dart.strong.expect | 12 ++ .../infer_local_function_return_type.dart | 20 +-- ...al_function_return_type.dart.strong.expect | 28 +-- .../inference/parameter_defaults_upwards.dart | 4 +- 13 files changed, 255 insertions(+), 175 deletions(-) create mode 100644 pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart create mode 100644 pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.direct.expect create mode 100644 pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.outline.expect create mode 100644 pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.strong.expect diff --git a/pkg/analyzer/test/src/task/strong/front_end_inference_test.dart b/pkg/analyzer/test/src/task/strong/front_end_inference_test.dart index 4eb4a57b37e..ffc750075ed 100644 --- a/pkg/analyzer/test/src/task/strong/front_end_inference_test.dart +++ b/pkg/analyzer/test/src/task/strong/front_end_inference_test.dart @@ -369,6 +369,30 @@ class _InstrumentationVisitor extends RecursiveAstVisitor { } } + @override + visitFunctionDeclaration(FunctionDeclaration node) { + super.visitFunctionDeclaration(node); + if (node.element is LocalElement && + node.element.enclosingElement is! CompilationUnitElement) { + if (node.returnType == null) { + _instrumentation.record( + uri, + node.name.offset, + 'returnType', + new _InstrumentationValueForType( + node.element.returnType, elementNamer)); + } + var parameters = node.functionExpression.parameters; + for (var parameter in parameters.parameters) { + // Note: it's tempting to check `parameter.type == null`, but that + // doesn't work because of function-typed formal parameter syntax. + if (parameter.element.hasImplicitType) { + _recordType(parameter.identifier.offset, parameter.element.type); + } + } + } + } + visitFunctionExpression(FunctionExpression node) { super.visitFunctionExpression(node); if (node.parent is! FunctionDeclaration) { diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart index 507f21c8133..99f2340a4c1 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -2432,10 +2432,14 @@ class BodyBuilder extends ScopeListener implements BuilderHelper { FunctionNode function = pop(); exitLocalScope(); var declaration = pop(); - var returnType = pop() ?? const DynamicType(); + var returnType = pop(); + var hasImplicitReturnType = returnType == null; + returnType ??= const DynamicType(); pop(); // Modifiers. exitFunction(); if (declaration is FunctionDeclaration) { + KernelFunctionDeclaration.setHasImplicitReturnType( + declaration, hasImplicitReturnType); function.returnType = returnType; declaration.variable.type = function.functionType; declaration.function = function; diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart index 966d8217bfd..c7b4bce4de4 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart @@ -25,11 +25,9 @@ import 'package:front_end/src/fasta/type_inference/type_inferrer.dart'; import 'package:front_end/src/fasta/type_inference/type_promotion.dart'; import 'package:front_end/src/fasta/type_inference/type_schema.dart'; import 'package:front_end/src/fasta/type_inference/type_schema_elimination.dart'; -import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart'; import 'package:kernel/ast.dart' hide InvalidExpression, InvalidInitializer, InvalidStatement; import 'package:kernel/frontend/accessors.dart'; -import 'package:kernel/type_algebra.dart'; import 'package:kernel/type_environment.dart'; import '../errors.dart' show internalError; @@ -715,31 +713,24 @@ class KernelForInStatement extends ForInStatement implements KernelStatement { /// form. class KernelFunctionDeclaration extends FunctionDeclaration implements KernelStatement { + bool _hasImplicitReturnType = false; + KernelFunctionDeclaration(VariableDeclaration variable, FunctionNode function) : super(variable, function); @override void _inferStatement(KernelTypeInferrer inferrer) { inferrer.listener.functionDeclarationEnter(this); - for (var parameter in function.positionalParameters) { - if (parameter.initializer != null) { - inferrer.inferExpression(parameter.initializer, parameter.type, false); - } - } - for (var parameter in function.namedParameters) { - if (parameter.initializer != null) { - inferrer.inferExpression(parameter.initializer, parameter.type, false); - } - } - if (!inferrer.isTopLevel) { - var oldClosureContext = inferrer.closureContext; - inferrer.closureContext = new ClosureContext( - inferrer, function.asyncMarker, function.returnType); - inferrer.inferStatement(function.body); - inferrer.closureContext = oldClosureContext; - } + inferrer.inferLocalFunction(function, null, false, fileOffset, + _hasImplicitReturnType ? null : function.returnType, true); + variable.type = function.functionType; inferrer.listener.functionDeclarationExit(this); } + + static void setHasImplicitReturnType( + KernelFunctionDeclaration declaration, bool hasImplicitReturnType) { + declaration._hasImplicitReturnType = hasImplicitReturnType; + } } /// Concrete shadow object representing a function expression in kernel form. @@ -774,137 +765,8 @@ class KernelFunctionExpression extends FunctionExpression KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { typeNeeded = inferrer.listener.functionExpressionEnter(this, typeContext) || typeNeeded; - - if (!inferrer.isTopLevel) { - for (var parameter in function.positionalParameters) { - if (parameter.initializer != null) { - inferrer.inferExpression( - parameter.initializer, parameter.type, false); - } - } - for (var parameter in function.namedParameters) { - if (parameter.initializer != null) { - inferrer.inferExpression( - parameter.initializer, parameter.type, false); - } - } - } - - // Let `` be the set of type parameters of the closure (with - // `n`=0 if there are no type parameters). - List typeParameters = function.typeParameters; - - // Let `(P0 x0, ..., Pm xm)` be the set of formal parameters of the closure - // (including required, positional optional, and named optional parameters). - // If any type `Pi` is missing, denote it as `_`. - List formals = function.positionalParameters.toList() - ..addAll(function.namedParameters); - - // Let `B` denote the closure body. If `B` is an expression function body - // (`=> e`), treat it as equivalent to a block function body containing a - // single `return` statement (`{ return e; }`). - - // Attempt to match `K` as a function type compatible with the closure (that - // is, one having n type parameters and a compatible set of formal - // parameters). If there is a successful match, let `` be the - // set of matched type parameters and `(Q0, ..., Qm)` be the set of matched - // formal parameter types, and let `N` be the return type. - Substitution substitution; - List formalTypesFromContext = - new List.filled(formals.length, null); - DartType returnContext; - if (inferrer.strongMode && typeContext is FunctionType) { - for (int i = 0; i < formals.length; i++) { - if (i < function.positionalParameters.length) { - formalTypesFromContext[i] = - getPositionalParameterType(typeContext, i); - } else { - formalTypesFromContext[i] = - getNamedParameterType(typeContext, formals[i].name); - } - } - returnContext = typeContext.returnType; - - // Let `[T/S]` denote the type substitution where each `Si` is replaced with - // the corresponding `Ti`. - var substitutionMap = {}; - for (int i = 0; i < typeContext.typeParameters.length; i++) { - substitutionMap[typeContext.typeParameters[i]] = - i < typeParameters.length - ? new TypeParameterType(typeParameters[i]) - : const DynamicType(); - } - substitution = Substitution.fromMap(substitutionMap); - } else { - // If the match is not successful because `K` is `_`, let all `Si`, all - // `Qi`, and `N` all be `_`. - - // If the match is not successful for any other reason, this will result in - // a type error, so the implementation is free to choose the best error - // recovery path. - substitution = Substitution.empty; - } - - // Define `Ri` as follows: if `Pi` is not `_`, let `Ri` be `Pi`. - // Otherwise, if `Qi` is not `_`, let `Ri` be the greatest closure of - // `Qi[T/S]` with respect to `?`. Otherwise, let `Ri` be `dynamic`. - for (int i = 0; i < formals.length; i++) { - KernelVariableDeclaration formal = formals[i]; - if (KernelVariableDeclaration.isImplicitlyTyped(formal)) { - DartType inferredType; - if (formalTypesFromContext[i] != null) { - inferredType = greatestClosure(inferrer.coreTypes, - substitution.substituteType(formalTypesFromContext[i])); - } else { - inferredType = const DynamicType(); - } - inferrer.instrumentation?.record( - Uri.parse(inferrer.uri), - formal.fileOffset, - 'type', - new InstrumentationValueForType(inferredType)); - formal.type = inferredType; - } - } - - // Let `N'` be `N[T/S]`. The [ClosureContext] constructor will adjust - // accordingly if the closure is declared with `async`, `async*`, or - // `sync*`. - if (returnContext != null) { - returnContext = substitution.substituteType(returnContext); - } - - // Apply type inference to `B` in return context `N’`, with any references - // to `xi` in `B` having type `Pi`. This produces `B’`. - bool isExpressionFunction = function.body is ReturnStatement; - bool needToSetReturnType = isExpressionFunction || inferrer.strongMode; - ClosureContext oldClosureContext = inferrer.closureContext; - ClosureContext closureContext = - new ClosureContext(inferrer, function.asyncMarker, returnContext); - inferrer.closureContext = closureContext; - inferrer.inferStatement(function.body); - - // If the closure is declared with `async*` or `sync*`, let `M` be the least - // upper bound of the types of the `yield` expressions in `B’`, or `void` if - // `B’` contains no `yield` expressions. Otherwise, let `M` be the least - // upper bound of the types of the `return` expressions in `B’`, or `void` - // if `B’` contains no `return` expressions. - DartType inferredReturnType; - if (needToSetReturnType || typeNeeded) { - inferredReturnType = - closureContext.inferReturnType(inferrer, isExpressionFunction); - } - - // Then the result of inference is `(R0 x0, ..., Rn xn) B` with - // type `(R0, ..., Rn) -> M’` (with some of the `Ri` and `xi` - // denoted as optional or named parameters, if appropriate). - if (needToSetReturnType) { - inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset, - 'returnType', new InstrumentationValueForType(inferredReturnType)); - function.returnType = inferredReturnType; - } - inferrer.closureContext = oldClosureContext; - var inferredType = typeNeeded ? function.functionType : null; + var inferredType = inferrer.inferLocalFunction( + function, typeContext, typeNeeded, fileOffset, null, false); inferrer.listener.functionExpressionExit(this, inferredType); return inferredType; } diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart index 34a3e3dc720..f9297c8267d 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart @@ -22,6 +22,7 @@ import 'package:kernel/ast.dart' DynamicType, Expression, Field, + FunctionNode, FunctionType, Initializer, InterfaceType, @@ -33,10 +34,12 @@ import 'package:kernel/ast.dart' ProcedureKind, PropertyGet, PropertySet, + ReturnStatement, Statement, SuperMethodInvocation, SuperPropertyGet, SuperPropertySet, + TypeParameter, TypeParameterType, VariableDeclaration, VoidType; @@ -637,6 +640,136 @@ abstract class TypeInferrerImpl extends TypeInferrer { return inferredType; } + DartType inferLocalFunction(FunctionNode function, DartType typeContext, + bool typeNeeded, int fileOffset, DartType returnContext, bool isNamed) { + bool hasImplicitReturnType = returnContext == null; + if (!isTopLevel) { + for (var parameter in function.positionalParameters) { + if (parameter.initializer != null) { + inferExpression(parameter.initializer, parameter.type, false); + } + } + for (var parameter in function.namedParameters) { + if (parameter.initializer != null) { + inferExpression(parameter.initializer, parameter.type, false); + } + } + } + + // Let `` be the set of type parameters of the closure (with + // `n`=0 if there are no type parameters). + List typeParameters = function.typeParameters; + + // Let `(P0 x0, ..., Pm xm)` be the set of formal parameters of the closure + // (including required, positional optional, and named optional parameters). + // If any type `Pi` is missing, denote it as `_`. + List formals = function.positionalParameters.toList() + ..addAll(function.namedParameters); + + // Let `B` denote the closure body. If `B` is an expression function body + // (`=> e`), treat it as equivalent to a block function body containing a + // single `return` statement (`{ return e; }`). + + // Attempt to match `K` as a function type compatible with the closure (that + // is, one having n type parameters and a compatible set of formal + // parameters). If there is a successful match, let `` be the + // set of matched type parameters and `(Q0, ..., Qm)` be the set of matched + // formal parameter types, and let `N` be the return type. + Substitution substitution; + List formalTypesFromContext = + new List.filled(formals.length, null); + if (strongMode && typeContext is FunctionType) { + for (int i = 0; i < formals.length; i++) { + if (i < function.positionalParameters.length) { + formalTypesFromContext[i] = + getPositionalParameterType(typeContext, i); + } else { + formalTypesFromContext[i] = + getNamedParameterType(typeContext, formals[i].name); + } + } + returnContext = typeContext.returnType; + + // Let `[T/S]` denote the type substitution where each `Si` is replaced + // with the corresponding `Ti`. + var substitutionMap = {}; + for (int i = 0; i < typeContext.typeParameters.length; i++) { + substitutionMap[typeContext.typeParameters[i]] = + i < typeParameters.length + ? new TypeParameterType(typeParameters[i]) + : const DynamicType(); + } + substitution = Substitution.fromMap(substitutionMap); + } else { + // If the match is not successful because `K` is `_`, let all `Si`, all + // `Qi`, and `N` all be `_`. + + // If the match is not successful for any other reason, this will result in + // a type error, so the implementation is free to choose the best error + // recovery path. + substitution = Substitution.empty; + } + + // Define `Ri` as follows: if `Pi` is not `_`, let `Ri` be `Pi`. + // Otherwise, if `Qi` is not `_`, let `Ri` be the greatest closure of + // `Qi[T/S]` with respect to `?`. Otherwise, let `Ri` be `dynamic`. + for (int i = 0; i < formals.length; i++) { + KernelVariableDeclaration formal = formals[i]; + if (KernelVariableDeclaration.isImplicitlyTyped(formal)) { + DartType inferredType; + if (formalTypesFromContext[i] != null) { + inferredType = greatestClosure(coreTypes, + substitution.substituteType(formalTypesFromContext[i])); + } else { + inferredType = const DynamicType(); + } + instrumentation?.record(Uri.parse(uri), formal.fileOffset, 'type', + new InstrumentationValueForType(inferredType)); + formal.type = inferredType; + } + } + + // Let `N'` be `N[T/S]`. The [ClosureContext] constructor will adjust + // accordingly if the closure is declared with `async`, `async*`, or + // `sync*`. + if (returnContext != null) { + returnContext = substitution.substituteType(returnContext); + } + + // Apply type inference to `B` in return context `N’`, with any references + // to `xi` in `B` having type `Pi`. This produces `B’`. + bool isExpressionFunction = function.body is ReturnStatement; + bool needToSetReturnType = hasImplicitReturnType && + ((isExpressionFunction && !isNamed) || strongMode); + ClosureContext oldClosureContext = this.closureContext; + ClosureContext closureContext = + new ClosureContext(this, function.asyncMarker, returnContext); + this.closureContext = closureContext; + inferStatement(function.body); + + // If the closure is declared with `async*` or `sync*`, let `M` be the least + // upper bound of the types of the `yield` expressions in `B’`, or `void` if + // `B’` contains no `yield` expressions. Otherwise, let `M` be the least + // upper bound of the types of the `return` expressions in `B’`, or `void` + // if `B’` contains no `return` expressions. + DartType inferredReturnType; + if (needToSetReturnType || typeNeeded) { + inferredReturnType = + closureContext.inferReturnType(this, isExpressionFunction); + } + + // Then the result of inference is `(R0 x0, ..., Rn xn) B` with + // type `(R0, ..., Rn) -> M’` (with some of the `Ri` and `xi` + // denoted as optional or named parameters, if appropriate). + if (needToSetReturnType) { + instrumentation?.record(Uri.parse(uri), fileOffset, 'returnType', + new InstrumentationValueForType(inferredReturnType)); + function.returnType = inferredReturnType; + } + this.closureContext = oldClosureContext; + return typeNeeded ? function.functionType : null; + } + /// Performs the core type inference algorithm for method invocations (this /// handles both null-aware and non-null-aware method invocations). DartType inferMethodInvocation( diff --git a/pkg/front_end/test/fasta/kompile.status b/pkg/front_end/test/fasta/kompile.status index d1ee977b029..63577397781 100644 --- a/pkg/front_end/test/fasta/kompile.status +++ b/pkg/front_end/test/fasta/kompile.status @@ -244,6 +244,7 @@ inference/infer_generic_method_type_required: Crash inference/infer_getter_cross_to_setter: Crash inference/infer_getter_from_later_inferred_getter: Crash inference/infer_list_literal_nested_in_map_literal: Crash +inference/infer_local_function_referenced_before_declaration: Crash inference/infer_local_function_return_type: Crash inference/infer_method_function_typed: Crash inference/infer_method_missing_params: Crash diff --git a/pkg/front_end/test/fasta/strong.status b/pkg/front_end/test/fasta/strong.status index fd965352fe4..ca8c14f738a 100644 --- a/pkg/front_end/test/fasta/strong.status +++ b/pkg/front_end/test/fasta/strong.status @@ -59,7 +59,6 @@ inference/downwards_inference_on_function_of_t_using_the_t: Fail inference/future_then_explicit_future: Fail inference/generic_functions_return_typedef: Fail inference/generic_methods_infer_js_builtin: Fail -inference/infer_local_function_return_type: Fail inference/infer_types_on_loop_indices_for_loop_with_inference: Fail inference/infer_use_of_void: Fail inference/list_literals_can_infer_null_top_level: Fail diff --git a/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart new file mode 100644 index 00000000000..3250f29739d --- /dev/null +++ b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart @@ -0,0 +1,20 @@ +// 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; + +test() { + /*@returnType=dynamic*/ f() => /*error:REFERENCED_BEFORE_DECLARATION*/ g(); + + // Ignore inference for g since Fasta doesn't infer it due to the circularity, + // and that's ok. + /*@testedFeatures=none*/ + g() => 0; + /*@testedFeatures=inference*/ + + var /*@type=() -> dynamic*/ v = f; +} + +main() {} diff --git a/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.direct.expect b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.direct.expect new file mode 100644 index 00000000000..eba78f82ba6 --- /dev/null +++ b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.direct.expect @@ -0,0 +1,12 @@ +library test; +import self as self; +import "dart:core" as core; + +const field dynamic #errors = const ["pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart:9:74: Error: Previous use of 'g'.\n /*@returnType=dynamic*/ f() => /*error:REFERENCED_BEFORE_DECLARATION*/ g();\n ^"]/* from null */; +static method test() → dynamic { + function f() → dynamic + return throw new core::NoSuchMethodError::_withType(null, #g, 32, [].toList(growable: false), {}, null); + const core::_ConstantExpressionError::•()._throw(new core::_CompileTimeError::•("pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart:14:3: Error: Can't declare 'g' because it was already used in this scope.\n g() => 0;\n ^")); + dynamic v = f; +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.outline.expect b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.outline.expect new file mode 100644 index 00000000000..8e85697c7a6 --- /dev/null +++ b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.outline.expect @@ -0,0 +1,7 @@ +library test; +import self as self; + +static method test() → dynamic + ; +static method main() → dynamic + ; diff --git a/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.strong.expect b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.strong.expect new file mode 100644 index 00000000000..cba1c4d9c58 --- /dev/null +++ b/pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart.strong.expect @@ -0,0 +1,12 @@ +library test; +import self as self; +import "dart:core" as core; + +const field dynamic #errors = const ["pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart:9:74: Error: Previous use of 'g'.\n /*@returnType=dynamic*/ f() => /*error:REFERENCED_BEFORE_DECLARATION*/ g();\n ^"]/* from null */; +static method test() → dynamic { + function f() → dynamic + return throw new core::NoSuchMethodError::_withType(null, #g, 32, [].toList(growable: false), {}, null); + const core::_ConstantExpressionError::•()._throw(new core::_CompileTimeError::•("pkg/front_end/testcases/inference/infer_local_function_referenced_before_declaration.dart:14:3: Error: Can't declare 'g' because it was already used in this scope.\n g() => 0;\n ^")); + () → dynamic v = f; +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart index a708bf85b83..f74c0c2198f 100644 --- a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart +++ b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart @@ -6,30 +6,29 @@ library test; test() { - f0() => 42; - f1() async => 42; + /*@returnType=int*/ f0() => 42; + /*@returnType=Future*/ f1() async => 42; - f2() { + /*@returnType=int*/ f2() { return 42; } - f3() async { + /*@returnType=Future*/ f3() async { return 42; } - f4() sync* { + /*@returnType=Iterable*/ f4() sync* { yield 42; } - f5() async* { + /*@returnType=Stream*/ f5() async* { yield 42; } num f6() => 42; - f7() => f7(); - f8() => /*error:REFERENCED_BEFORE_DECLARATION*/ f9(); - f9() => f5(); + /*@returnType=dynamic*/ f7() => f7(); + /*@returnType=Stream*/ f8() => f5(); var /*@type=() -> int*/ v0 = f0; var /*@type=() -> Future*/ v1 = f1; @@ -39,8 +38,7 @@ test() { var /*@type=() -> Stream*/ v5 = f5; var /*@type=() -> num*/ v6 = f6; var /*@type=() -> dynamic*/ v7 = f7; - var /*@type=() -> dynamic*/ v8 = f8; - var /*@type=() -> Stream*/ v9 = f9; + var /*@type=() -> Stream*/ v8 = f8; } main() {} diff --git a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.expect b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.expect index 0f610b5949b..13b68a191d7 100644 --- a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.expect +++ b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.expect @@ -1,31 +1,39 @@ library test; import self as self; import "dart:core" as core; +import "dart:async" as asy; -const field dynamic #errors = const ["pkg/front_end/testcases/inference/infer_local_function_return_type.dart:31:51: Error: Previous use of 'f9'.\n f8() => /*error:REFERENCED_BEFORE_DECLARATION*/ f9();\n ^"]/* from null */; static method test() → dynamic { - function f0() → dynamic + function f0() → core::int return 42; - function f1() → dynamic async + function f1() → asy::Future async return 42; - function f2() → dynamic { + function f2() → core::int { return 42; } - function f3() → dynamic async { + function f3() → asy::Future async { return 42; } - function f4() → dynamic sync* { + function f4() → core::Iterable sync* { yield 42; } - function f5() → dynamic async* { + function f5() → asy::Stream async* { yield 42; } function f6() → core::num return 42; function f7() → dynamic return f7.call(); - function f8() → dynamic - return throw new core::NoSuchMethodError::_withType(null, #f9, 32, [].toList(growable: false), {}, null); - const core::_ConstantExpressionError::•()._throw(new core::_CompileTimeError::•("pkg/front_end/testcases/inference/infer_local_function_return_type.dart:32:3: Error: Can't declare 'f9' because it was already used in this scope.\n f9() => f5();\n ^")); + function f8() → asy::Stream + return f5.call(); + () → core::int v0 = f0; + () → asy::Future v1 = f1; + () → core::int v2 = f2; + () → asy::Future v3 = f3; + () → core::Iterable v4 = f4; + () → asy::Stream v5 = f5; + () → core::num v6 = f6; + () → dynamic v7 = f7; + () → asy::Stream v8 = f8; } static method main() → dynamic {} diff --git a/pkg/front_end/testcases/inference/parameter_defaults_upwards.dart b/pkg/front_end/testcases/inference/parameter_defaults_upwards.dart index 8ed6133f1ea..a19a41ce5ec 100644 --- a/pkg/front_end/testcases/inference/parameter_defaults_upwards.dart +++ b/pkg/front_end/testcases/inference/parameter_defaults_upwards.dart @@ -15,8 +15,8 @@ void optional_toplevel([x = /*@typeArgs=int*/ const [0]]) {} void named_toplevel({x: /*@typeArgs=int*/ const [0]}) {} main() { - void optional_local([x = /*@typeArgs=int*/ const [0]]) {} - void named_local({x: /*@typeArgs=int*/ const [0]}) {} + void optional_local([/*@type=dynamic*/ x = /*@typeArgs=int*/ const [0]]) {} + void named_local({/*@type=dynamic*/ x: /*@typeArgs=int*/ const [0]}) {} var /*@type=C*/ c_optional_toplevel = new /*@typeArgs=dynamic*/ C.optional(optional_toplevel); var /*@type=C*/ c_named_toplevel =