blob: 25c841512a8090461e24a736233fb44b8c70a569 [file] [log] [blame]
// 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.
import 'package:compiler/src/closure.dart';
import 'package:compiler/src/common.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/tree/nodes.dart' as ast;
import 'package:compiler/src/types/types.dart';
import 'package:compiler/src/js_model/locals.dart';
import 'package:compiler/src/kernel/element_map.dart';
import 'package:compiler/src/kernel/kernel_backend_strategy.dart';
import 'package:kernel/ast.dart' as ir;
import '../equivalence/id_equivalence.dart';
/// Compute type inference data for [_member] as a [MemberElement].
///
/// Fills [actualMap] with the data.
void computeMemberAstTypeMasks(
Compiler compiler, MemberEntity _member, Map<Id, ActualData> actualMap,
{bool verbose: false}) {
MemberElement member = _member;
ResolvedAst resolvedAst = member.resolvedAst;
compiler.reporter.withCurrentElement(member.implementation, () {
new TypeMaskAstComputer(compiler.reporter, actualMap, resolvedAst,
compiler.globalInference.results)
.run();
});
}
abstract class ComputeValueMixin<T> {
GlobalTypeInferenceResults<T> get results;
String getMemberValue(MemberEntity member) {
GlobalTypeInferenceMemberResult<T> memberResult =
results.resultOfMember(member);
return getTypeMaskValue(member.isFunction || member.isConstructor
? memberResult.returnType
: memberResult.type);
}
String getParameterValue(Local parameter) {
GlobalTypeInferenceParameterResult<T> elementResult =
results.resultOfParameter(parameter);
return getTypeMaskValue(elementResult.type);
}
String getTypeMaskValue(TypeMask typeMask) {
return typeMask != null ? '$typeMask' : null;
}
}
/// AST visitor for computing inference data for a member.
class TypeMaskAstComputer extends AstDataExtractor
with ComputeValueMixin<ast.Node> {
final GlobalTypeInferenceResults<ast.Node> results;
final GlobalTypeInferenceElementResult<ast.Node> result;
TypeMaskAstComputer(DiagnosticReporter reporter,
Map<Id, ActualData> actualMap, ResolvedAst resolvedAst, this.results)
: result = results.resultOfMember(resolvedAst.element as MemberElement),
super(reporter, actualMap, resolvedAst);
@override
String computeElementValue(Id id, AstElement element) {
if (element.isParameter) {
ParameterElement parameter = element;
return getParameterValue(parameter);
} else if (element.isLocal && element.isFunction) {
LocalFunctionElement localFunction = element;
return getMemberValue(localFunction.callMethod);
} else {
MemberElement member = element;
return getMemberValue(member);
}
}
@override
String computeNodeValue(Id id, ast.Node node, [AstElement element]) {
if (element != null && element.isLocal && element.isFunction) {
return computeElementValue(id, element);
} else if (element != null && element.isParameter) {
return computeElementValue(id, element);
} else if (node is ast.SendSet) {
if (id.kind == IdKind.invoke) {
return getTypeMaskValue(result.typeOfOperator(node));
} else if (id.kind == IdKind.update) {
return getTypeMaskValue(result.typeOfSend(node));
} else if (id.kind == IdKind.node) {
return getTypeMaskValue(result.typeOfGetter(node));
}
} else if (node is ast.Send) {
return getTypeMaskValue(result.typeOfSend(node));
} else if (node is ast.ForIn) {
if (id.kind == IdKind.iterator) {
return getTypeMaskValue(result.typeOfIterator(node));
} else if (id.kind == IdKind.current) {
return getTypeMaskValue(result.typeOfIteratorCurrent(node));
} else if (id.kind == IdKind.moveNext) {
return getTypeMaskValue(result.typeOfIteratorMoveNext(node));
}
}
return null;
}
}
/// Compute type inference data for [member] from kernel based inference.
///
/// Fills [actualMap] with the data.
void computeMemberIrTypeMasks(
Compiler compiler, MemberEntity member, Map<Id, ActualData> actualMap,
{bool verbose: false}) {
KernelBackendStrategy backendStrategy = compiler.backendStrategy;
KernelToElementMapForBuilding elementMap = backendStrategy.elementMap;
GlobalLocalsMap localsMap = backendStrategy.globalLocalsMapForTesting;
MemberDefinition definition = elementMap.getMemberDefinition(member);
new TypeMaskIrComputer(
compiler.reporter,
actualMap,
elementMap,
member,
localsMap.getLocalsMap(member),
compiler.globalInference.results,
backendStrategy.closureDataLookup as ClosureDataLookup<ir.Node>)
.run(definition.node);
}
/// AST visitor for computing inference data for a member.
class TypeMaskIrComputer extends IrDataExtractor
with ComputeValueMixin<ir.Node> {
final GlobalTypeInferenceResults<ir.Node> results;
final GlobalTypeInferenceElementResult<ir.Node> result;
final KernelToElementMapForBuilding _elementMap;
final KernelToLocalsMap _localsMap;
final ClosureDataLookup<ir.Node> _closureDataLookup;
TypeMaskIrComputer(
DiagnosticReporter reporter,
Map<Id, ActualData> actualMap,
this._elementMap,
MemberEntity member,
this._localsMap,
this.results,
this._closureDataLookup)
: result = results.resultOfMember(member),
super(reporter, actualMap);
@override
String computeMemberValue(Id id, ir.Member node) {
return getMemberValue(_elementMap.getMember(node));
}
@override
String computeNodeValue(Id id, ir.TreeNode node) {
if (node is ir.VariableDeclaration && node.parent is ir.FunctionNode) {
Local parameter = _localsMap.getLocalVariable(node);
return getParameterValue(parameter);
} else if (node is ir.FunctionExpression ||
node is ir.FunctionDeclaration) {
ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node);
return getMemberValue(info.callMethod);
} else if (node is ir.MethodInvocation) {
return getTypeMaskValue(result.typeOfSend(node));
} else if (node is ir.PropertyGet) {
return getTypeMaskValue(result.typeOfGetter(node));
} else if (node is ir.PropertySet) {
return getTypeMaskValue(result.typeOfSend(node));
} else if (node is ir.ForInStatement) {
if (id.kind == IdKind.iterator) {
return getTypeMaskValue(result.typeOfIterator(node));
} else if (id.kind == IdKind.current) {
return getTypeMaskValue(result.typeOfIteratorCurrent(node));
} else if (id.kind == IdKind.moveNext) {
return getTypeMaskValue(result.typeOfIteratorMoveNext(node));
}
}
return null;
}
}