mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:57:35 +00:00
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 .
This commit is contained in:
parent
ec8505fc79
commit
dd0a00f581
|
@ -369,6 +369,30 @@ class _InstrumentationVisitor extends RecursiveAstVisitor<Null> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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) {
|
visitFunctionExpression(FunctionExpression node) {
|
||||||
super.visitFunctionExpression(node);
|
super.visitFunctionExpression(node);
|
||||||
if (node.parent is! FunctionDeclaration) {
|
if (node.parent is! FunctionDeclaration) {
|
||||||
|
|
|
@ -2432,10 +2432,14 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||||
FunctionNode function = pop();
|
FunctionNode function = pop();
|
||||||
exitLocalScope();
|
exitLocalScope();
|
||||||
var declaration = pop();
|
var declaration = pop();
|
||||||
var returnType = pop() ?? const DynamicType();
|
var returnType = pop();
|
||||||
|
var hasImplicitReturnType = returnType == null;
|
||||||
|
returnType ??= const DynamicType();
|
||||||
pop(); // Modifiers.
|
pop(); // Modifiers.
|
||||||
exitFunction();
|
exitFunction();
|
||||||
if (declaration is FunctionDeclaration) {
|
if (declaration is FunctionDeclaration) {
|
||||||
|
KernelFunctionDeclaration.setHasImplicitReturnType(
|
||||||
|
declaration, hasImplicitReturnType);
|
||||||
function.returnType = returnType;
|
function.returnType = returnType;
|
||||||
declaration.variable.type = function.functionType;
|
declaration.variable.type = function.functionType;
|
||||||
declaration.function = function;
|
declaration.function = function;
|
||||||
|
|
|
@ -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_promotion.dart';
|
||||||
import 'package:front_end/src/fasta/type_inference/type_schema.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_elimination.dart';
|
||||||
import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart';
|
|
||||||
import 'package:kernel/ast.dart'
|
import 'package:kernel/ast.dart'
|
||||||
hide InvalidExpression, InvalidInitializer, InvalidStatement;
|
hide InvalidExpression, InvalidInitializer, InvalidStatement;
|
||||||
import 'package:kernel/frontend/accessors.dart';
|
import 'package:kernel/frontend/accessors.dart';
|
||||||
import 'package:kernel/type_algebra.dart';
|
|
||||||
import 'package:kernel/type_environment.dart';
|
import 'package:kernel/type_environment.dart';
|
||||||
|
|
||||||
import '../errors.dart' show internalError;
|
import '../errors.dart' show internalError;
|
||||||
|
@ -715,31 +713,24 @@ class KernelForInStatement extends ForInStatement implements KernelStatement {
|
||||||
/// form.
|
/// form.
|
||||||
class KernelFunctionDeclaration extends FunctionDeclaration
|
class KernelFunctionDeclaration extends FunctionDeclaration
|
||||||
implements KernelStatement {
|
implements KernelStatement {
|
||||||
|
bool _hasImplicitReturnType = false;
|
||||||
|
|
||||||
KernelFunctionDeclaration(VariableDeclaration variable, FunctionNode function)
|
KernelFunctionDeclaration(VariableDeclaration variable, FunctionNode function)
|
||||||
: super(variable, function);
|
: super(variable, function);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void _inferStatement(KernelTypeInferrer inferrer) {
|
void _inferStatement(KernelTypeInferrer inferrer) {
|
||||||
inferrer.listener.functionDeclarationEnter(this);
|
inferrer.listener.functionDeclarationEnter(this);
|
||||||
for (var parameter in function.positionalParameters) {
|
inferrer.inferLocalFunction(function, null, false, fileOffset,
|
||||||
if (parameter.initializer != null) {
|
_hasImplicitReturnType ? null : function.returnType, true);
|
||||||
inferrer.inferExpression(parameter.initializer, parameter.type, false);
|
variable.type = function.functionType;
|
||||||
}
|
|
||||||
}
|
|
||||||
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.listener.functionDeclarationExit(this);
|
inferrer.listener.functionDeclarationExit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setHasImplicitReturnType(
|
||||||
|
KernelFunctionDeclaration declaration, bool hasImplicitReturnType) {
|
||||||
|
declaration._hasImplicitReturnType = hasImplicitReturnType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Concrete shadow object representing a function expression in kernel form.
|
/// Concrete shadow object representing a function expression in kernel form.
|
||||||
|
@ -774,137 +765,8 @@ class KernelFunctionExpression extends FunctionExpression
|
||||||
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
|
KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
|
||||||
typeNeeded = inferrer.listener.functionExpressionEnter(this, typeContext) ||
|
typeNeeded = inferrer.listener.functionExpressionEnter(this, typeContext) ||
|
||||||
typeNeeded;
|
typeNeeded;
|
||||||
|
var inferredType = inferrer.inferLocalFunction(
|
||||||
if (!inferrer.isTopLevel) {
|
function, typeContext, typeNeeded, fileOffset, null, false);
|
||||||
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 `<T0, ..., Tn>` be the set of type parameters of the closure (with
|
|
||||||
// `n`=0 if there are no type parameters).
|
|
||||||
List<TypeParameter> 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<VariableDeclaration> 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 `<S0, ..., Sn>` 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<DartType> formalTypesFromContext =
|
|
||||||
new List<DartType>.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 = <TypeParameter, DartType>{};
|
|
||||||
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 `<T0, ..., Tn>(R0 x0, ..., Rn xn) B` with
|
|
||||||
// type `<T0, ..., Tn>(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;
|
|
||||||
inferrer.listener.functionExpressionExit(this, inferredType);
|
inferrer.listener.functionExpressionExit(this, inferredType);
|
||||||
return inferredType;
|
return inferredType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import 'package:kernel/ast.dart'
|
||||||
DynamicType,
|
DynamicType,
|
||||||
Expression,
|
Expression,
|
||||||
Field,
|
Field,
|
||||||
|
FunctionNode,
|
||||||
FunctionType,
|
FunctionType,
|
||||||
Initializer,
|
Initializer,
|
||||||
InterfaceType,
|
InterfaceType,
|
||||||
|
@ -33,10 +34,12 @@ import 'package:kernel/ast.dart'
|
||||||
ProcedureKind,
|
ProcedureKind,
|
||||||
PropertyGet,
|
PropertyGet,
|
||||||
PropertySet,
|
PropertySet,
|
||||||
|
ReturnStatement,
|
||||||
Statement,
|
Statement,
|
||||||
SuperMethodInvocation,
|
SuperMethodInvocation,
|
||||||
SuperPropertyGet,
|
SuperPropertyGet,
|
||||||
SuperPropertySet,
|
SuperPropertySet,
|
||||||
|
TypeParameter,
|
||||||
TypeParameterType,
|
TypeParameterType,
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
VoidType;
|
VoidType;
|
||||||
|
@ -637,6 +640,136 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
||||||
return inferredType;
|
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 `<T0, ..., Tn>` be the set of type parameters of the closure (with
|
||||||
|
// `n`=0 if there are no type parameters).
|
||||||
|
List<TypeParameter> 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<VariableDeclaration> 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 `<S0, ..., Sn>` 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<DartType> formalTypesFromContext =
|
||||||
|
new List<DartType>.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 = <TypeParameter, DartType>{};
|
||||||
|
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 `<T0, ..., Tn>(R0 x0, ..., Rn xn) B` with
|
||||||
|
// type `<T0, ..., Tn>(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
|
/// Performs the core type inference algorithm for method invocations (this
|
||||||
/// handles both null-aware and non-null-aware method invocations).
|
/// handles both null-aware and non-null-aware method invocations).
|
||||||
DartType inferMethodInvocation(
|
DartType inferMethodInvocation(
|
||||||
|
|
|
@ -244,6 +244,7 @@ inference/infer_generic_method_type_required: Crash
|
||||||
inference/infer_getter_cross_to_setter: Crash
|
inference/infer_getter_cross_to_setter: Crash
|
||||||
inference/infer_getter_from_later_inferred_getter: Crash
|
inference/infer_getter_from_later_inferred_getter: Crash
|
||||||
inference/infer_list_literal_nested_in_map_literal: 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_local_function_return_type: Crash
|
||||||
inference/infer_method_function_typed: Crash
|
inference/infer_method_function_typed: Crash
|
||||||
inference/infer_method_missing_params: Crash
|
inference/infer_method_missing_params: Crash
|
||||||
|
|
|
@ -59,7 +59,6 @@ inference/downwards_inference_on_function_of_t_using_the_t: Fail
|
||||||
inference/future_then_explicit_future: Fail
|
inference/future_then_explicit_future: Fail
|
||||||
inference/generic_functions_return_typedef: Fail
|
inference/generic_functions_return_typedef: Fail
|
||||||
inference/generic_methods_infer_js_builtin: 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_types_on_loop_indices_for_loop_with_inference: Fail
|
||||||
inference/infer_use_of_void: Fail
|
inference/infer_use_of_void: Fail
|
||||||
inference/list_literals_can_infer_null_top_level: Fail
|
inference/list_literals_can_infer_null_top_level: Fail
|
||||||
|
|
|
@ -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() {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
library test;
|
||||||
|
import self as self;
|
||||||
|
import "dart:core" as core;
|
||||||
|
|
||||||
|
const field dynamic #errors = const <dynamic>["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, <dynamic>[].toList(growable: false), <dynamic, dynamic>{}, 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 {}
|
|
@ -0,0 +1,7 @@
|
||||||
|
library test;
|
||||||
|
import self as self;
|
||||||
|
|
||||||
|
static method test() → dynamic
|
||||||
|
;
|
||||||
|
static method main() → dynamic
|
||||||
|
;
|
|
@ -0,0 +1,12 @@
|
||||||
|
library test;
|
||||||
|
import self as self;
|
||||||
|
import "dart:core" as core;
|
||||||
|
|
||||||
|
const field dynamic #errors = const <dynamic>["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, <dynamic>[].toList(growable: false), <dynamic, dynamic>{}, 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 {}
|
|
@ -6,30 +6,29 @@
|
||||||
library test;
|
library test;
|
||||||
|
|
||||||
test() {
|
test() {
|
||||||
f0() => 42;
|
/*@returnType=int*/ f0() => 42;
|
||||||
f1() async => 42;
|
/*@returnType=Future<int>*/ f1() async => 42;
|
||||||
|
|
||||||
f2() {
|
/*@returnType=int*/ f2() {
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
f3() async {
|
/*@returnType=Future<int>*/ f3() async {
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
f4() sync* {
|
/*@returnType=Iterable<int>*/ f4() sync* {
|
||||||
yield 42;
|
yield 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
f5() async* {
|
/*@returnType=Stream<int>*/ f5() async* {
|
||||||
yield 42;
|
yield 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
num f6() => 42;
|
num f6() => 42;
|
||||||
|
|
||||||
f7() => f7();
|
/*@returnType=dynamic*/ f7() => f7();
|
||||||
f8() => /*error:REFERENCED_BEFORE_DECLARATION*/ f9();
|
/*@returnType=Stream<int>*/ f8() => f5();
|
||||||
f9() => f5();
|
|
||||||
|
|
||||||
var /*@type=() -> int*/ v0 = f0;
|
var /*@type=() -> int*/ v0 = f0;
|
||||||
var /*@type=() -> Future<int>*/ v1 = f1;
|
var /*@type=() -> Future<int>*/ v1 = f1;
|
||||||
|
@ -39,8 +38,7 @@ test() {
|
||||||
var /*@type=() -> Stream<int>*/ v5 = f5;
|
var /*@type=() -> Stream<int>*/ v5 = f5;
|
||||||
var /*@type=() -> num*/ v6 = f6;
|
var /*@type=() -> num*/ v6 = f6;
|
||||||
var /*@type=() -> dynamic*/ v7 = f7;
|
var /*@type=() -> dynamic*/ v7 = f7;
|
||||||
var /*@type=() -> dynamic*/ v8 = f8;
|
var /*@type=() -> Stream<int>*/ v8 = f8;
|
||||||
var /*@type=() -> Stream<int>*/ v9 = f9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {}
|
main() {}
|
||||||
|
|
|
@ -1,31 +1,39 @@
|
||||||
library test;
|
library test;
|
||||||
import self as self;
|
import self as self;
|
||||||
import "dart:core" as core;
|
import "dart:core" as core;
|
||||||
|
import "dart:async" as asy;
|
||||||
|
|
||||||
const field dynamic #errors = const <dynamic>["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 {
|
static method test() → dynamic {
|
||||||
function f0() → dynamic
|
function f0() → core::int
|
||||||
return 42;
|
return 42;
|
||||||
function f1() → dynamic async
|
function f1() → asy::Future<core::int> async
|
||||||
return 42;
|
return 42;
|
||||||
function f2() → dynamic {
|
function f2() → core::int {
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
function f3() → dynamic async {
|
function f3() → asy::Future<core::int> async {
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
function f4() → dynamic sync* {
|
function f4() → core::Iterable<core::int> sync* {
|
||||||
yield 42;
|
yield 42;
|
||||||
}
|
}
|
||||||
function f5() → dynamic async* {
|
function f5() → asy::Stream<core::int> async* {
|
||||||
yield 42;
|
yield 42;
|
||||||
}
|
}
|
||||||
function f6() → core::num
|
function f6() → core::num
|
||||||
return 42;
|
return 42;
|
||||||
function f7() → dynamic
|
function f7() → dynamic
|
||||||
return f7.call();
|
return f7.call();
|
||||||
function f8() → dynamic
|
function f8() → asy::Stream<core::int>
|
||||||
return throw new core::NoSuchMethodError::_withType(null, #f9, 32, <dynamic>[].toList(growable: false), <dynamic, dynamic>{}, null);
|
return f5.call();
|
||||||
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 ^"));
|
() → core::int v0 = f0;
|
||||||
|
() → asy::Future<core::int> v1 = f1;
|
||||||
|
() → core::int v2 = f2;
|
||||||
|
() → asy::Future<core::int> v3 = f3;
|
||||||
|
() → core::Iterable<core::int> v4 = f4;
|
||||||
|
() → asy::Stream<core::int> v5 = f5;
|
||||||
|
() → core::num v6 = f6;
|
||||||
|
() → dynamic v7 = f7;
|
||||||
|
() → asy::Stream<core::int> v8 = f8;
|
||||||
}
|
}
|
||||||
static method main() → dynamic {}
|
static method main() → dynamic {}
|
||||||
|
|
|
@ -15,8 +15,8 @@ void optional_toplevel([x = /*@typeArgs=int*/ const [0]]) {}
|
||||||
void named_toplevel({x: /*@typeArgs=int*/ const [0]}) {}
|
void named_toplevel({x: /*@typeArgs=int*/ const [0]}) {}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
void optional_local([x = /*@typeArgs=int*/ const [0]]) {}
|
void optional_local([/*@type=dynamic*/ x = /*@typeArgs=int*/ const [0]]) {}
|
||||||
void named_local({x: /*@typeArgs=int*/ const [0]}) {}
|
void named_local({/*@type=dynamic*/ x: /*@typeArgs=int*/ const [0]}) {}
|
||||||
var /*@type=C<dynamic>*/ c_optional_toplevel =
|
var /*@type=C<dynamic>*/ c_optional_toplevel =
|
||||||
new /*@typeArgs=dynamic*/ C.optional(optional_toplevel);
|
new /*@typeArgs=dynamic*/ C.optional(optional_toplevel);
|
||||||
var /*@type=C<dynamic>*/ c_named_toplevel =
|
var /*@type=C<dynamic>*/ c_named_toplevel =
|
||||||
|
|
Loading…
Reference in a new issue