blob: fd0080fd231836a9e938866e56a001d2a5804a62 [file] [log] [blame]
// Copyright (c) 2015, 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.
library dart2js.resolution.tree_elements;
import '../common.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../diagnostics/source_span.dart';
import '../elements/elements.dart';
import '../tree/tree.dart';
import '../universe/selector.dart' show Selector;
import '../util/util.dart';
import 'secret_tree_element.dart' show getTreeElement, setTreeElement;
import 'send_structure.dart';
abstract class TreeElements {
AnalyzableElement get analyzedElement;
Iterable<SourceSpan> get superUses;
void forEachConstantNode(f(Node n, ConstantExpression c));
Element operator [](Node node);
Map<Node, DartType> get typesCache;
/// Returns the [SendStructure] that describes the semantics of [node].
SendStructure getSendStructure(Send node);
/// Returns the [NewStructure] that describes the semantics of [node].
NewStructure getNewStructure(NewExpression node);
// TODO(johnniwinther): Investigate whether [Node] could be a [Send].
Selector getSelector(Node node);
Selector getGetterSelectorInComplexSendSet(SendSet node);
Selector getOperatorSelectorInComplexSendSet(SendSet node);
DartType getType(Node node);
/// Returns the for-in loop variable for [node].
Element getForInVariable(ForIn node);
void setConstant(Node node, ConstantExpression constant);
ConstantExpression getConstant(Node node);
/// Returns the [FunctionElement] defined by [node].
FunctionElement getFunctionDefinition(FunctionExpression node);
/// Returns target constructor for the redirecting factory body [node].
ConstructorElement getRedirectingTargetConstructor(
RedirectingFactoryBody node);
/**
* Returns [:true:] if [node] is a type literal.
*
* Resolution marks this by setting the type on the node to be the
* type that the literal refers to.
*/
bool isTypeLiteral(Send node);
/// Returns the type that the type literal [node] refers to.
DartType getTypeLiteralType(Send node);
/// Returns a list of nodes that potentially mutate [element] anywhere in its
/// scope.
List<Node> getPotentialMutations(VariableElement element);
/// Returns a list of nodes that potentially mutate [element] in [node].
List<Node> getPotentialMutationsIn(Node node, VariableElement element);
/// Returns a list of nodes that potentially mutate [element] in a closure.
List<Node> getPotentialMutationsInClosure(VariableElement element);
/// Returns a list of nodes that access [element] within a closure in [node].
List<Node> getAccessesByClosureIn(Node node, VariableElement element);
/// Returns the jump target defined by [node].
JumpTarget getTargetDefinition(Node node);
/// Returns the jump target of the [node].
JumpTarget getTargetOf(GotoStatement node);
/// Returns the label defined by [node].
LabelDefinition getLabelDefinition(Label node);
/// Returns the label that [node] targets.
LabelDefinition getTargetLabel(GotoStatement node);
/// `true` if the [analyzedElement]'s source code contains a [TryStatement].
bool get containsTryStatement;
/// Returns native data stored with [node].
getNativeData(Node node);
}
class TreeElementMapping extends TreeElements {
final AnalyzableElement analyzedElement;
Map<Spannable, Selector> _selectors;
Map<Node, DartType> _types;
Map<Node, DartType> _typesCache;
Map<Node, DartType> get typesCache => _typesCache ??= <Node, DartType>{};
Setlet<SourceSpan> _superUses;
Map<Node, ConstantExpression> _constants;
Map<VariableElement, List<Node>> _potentiallyMutated;
Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn;
Map<VariableElement, List<Node>> _potentiallyMutatedInClosure;
Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn;
Maplet<Send, SendStructure> _sendStructureMap;
Maplet<NewExpression, NewStructure> _newStructureMap;
bool containsTryStatement = false;
/// Map from nodes to the targets they define.
Map<Node, JumpTarget> _definedTargets;
/// Map from goto statements to their targets.
Map<GotoStatement, JumpTarget> _usedTargets;
/// Map from labels to their label definition.
Map<Label, LabelDefinition> _definedLabels;
/// Map from labeled goto statements to the labels they target.
Map<GotoStatement, LabelDefinition> _targetLabels;
/// Map from nodes to native data.
Map<Node, dynamic> _nativeData;
final int hashCode = _hashCodeCounter = (_hashCodeCounter + 1).toUnsigned(30);
static int _hashCodeCounter = 0;
TreeElementMapping(this.analyzedElement);
operator []=(Node node, Element element) {
// TODO(johnniwinther): Simplify this invariant to use only declarations in
// [TreeElements].
assert(invariant(node, () {
if (!element.isMalformed && analyzedElement != null && element.isPatch) {
return analyzedElement.implementationLibrary.isPatch;
}
return true;
}));
// TODO(ahe): Investigate why the invariant below doesn't hold.
// assert(invariant(node,
// getTreeElement(node) == element ||
// getTreeElement(node) == null,
// message: '${getTreeElement(node)}; $element'));
setTreeElement(node, element);
}
@override
operator [](Node node) => getTreeElement(node);
@override
SendStructure getSendStructure(Send node) {
if (_sendStructureMap == null) return null;
return _sendStructureMap[node];
}
void setSendStructure(Send node, SendStructure sendStructure) {
if (_sendStructureMap == null) {
_sendStructureMap = new Maplet<Send, SendStructure>();
}
_sendStructureMap[node] = sendStructure;
}
@override
NewStructure getNewStructure(NewExpression node) {
if (_newStructureMap == null) return null;
return _newStructureMap[node];
}
void setNewStructure(NewExpression node, NewStructure newStructure) {
if (_newStructureMap == null) {
_newStructureMap = new Maplet<NewExpression, NewStructure>();
}
_newStructureMap[node] = newStructure;
}
void setType(Node node, DartType type) {
if (_types == null) {
_types = new Maplet<Node, DartType>();
}
_types[node] = type;
}
@override
DartType getType(Node node) => _types != null ? _types[node] : null;
@override
Iterable<SourceSpan> get superUses {
return _superUses != null ? _superUses : const <SourceSpan>[];
}
void addSuperUse(SourceSpan span) {
if (_superUses == null) {
_superUses = new Setlet<SourceSpan>();
}
_superUses.add(span);
}
Selector _getSelector(Spannable node) {
return _selectors != null ? _selectors[node] : null;
}
void _setSelector(Spannable node, Selector selector) {
if (_selectors == null) {
_selectors = new Maplet<Spannable, Selector>();
}
_selectors[node] = selector;
}
void setSelector(Node node, Selector selector) {
_setSelector(node, selector);
}
@override
Selector getSelector(Node node) => _getSelector(node);
int getSelectorCount() => _selectors == null ? 0 : _selectors.length;
void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) {
_setSelector(node.selector, selector);
}
@override
Selector getGetterSelectorInComplexSendSet(SendSet node) {
return _getSelector(node.selector);
}
void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) {
_setSelector(node.assignmentOperator, selector);
}
@override
Selector getOperatorSelectorInComplexSendSet(SendSet node) {
return _getSelector(node.assignmentOperator);
}
@override
Element getForInVariable(ForIn node) {
return this[node];
}
@override
void setConstant(Node node, ConstantExpression constant) {
if (_constants == null) {
_constants = new Maplet<Node, ConstantExpression>();
}
_constants[node] = constant;
}
@override
ConstantExpression getConstant(Node node) {
return _constants != null ? _constants[node] : null;
}
@override
bool isTypeLiteral(Send node) {
return getType(node) != null;
}
@override
DartType getTypeLiteralType(Send node) {
return getType(node);
}
@override
List<Node> getPotentialMutations(VariableElement element) {
if (_potentiallyMutated == null) return const <Node>[];
List<Node> mutations = _potentiallyMutated[element];
if (mutations == null) return const <Node>[];
return mutations;
}
void registerPotentialMutation(VariableElement element, Node mutationNode) {
if (_potentiallyMutated == null) {
_potentiallyMutated = new Maplet<VariableElement, List<Node>>();
}
_potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
}
@override
List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
if (_potentiallyMutatedIn == null) return const <Node>[];
Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
if (mutationsIn == null) return const <Node>[];
List<Node> mutations = mutationsIn[element];
if (mutations == null) return const <Node>[];
return mutations;
}
void registerPotentialMutationIn(
Node contextNode, VariableElement element, Node mutationNode) {
if (_potentiallyMutatedIn == null) {
_potentiallyMutatedIn =
new Maplet<Node, Map<VariableElement, List<Node>>>();
}
Map<VariableElement, List<Node>> mutationMap =
_potentiallyMutatedIn.putIfAbsent(
contextNode, () => new Maplet<VariableElement, List<Node>>());
mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
}
@override
List<Node> getPotentialMutationsInClosure(VariableElement element) {
if (_potentiallyMutatedInClosure == null) return const <Node>[];
List<Node> mutations = _potentiallyMutatedInClosure[element];
if (mutations == null) return const <Node>[];
return mutations;
}
void registerPotentialMutationInClosure(
VariableElement element, Node mutationNode) {
if (_potentiallyMutatedInClosure == null) {
_potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>();
}
_potentiallyMutatedInClosure
.putIfAbsent(element, () => <Node>[])
.add(mutationNode);
}
@override
List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
if (_accessedByClosureIn == null) return const <Node>[];
Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
if (accessesIn == null) return const <Node>[];
List<Node> accesses = accessesIn[element];
if (accesses == null) return const <Node>[];
return accesses;
}
void setAccessedByClosureIn(
Node contextNode, VariableElement element, Node accessNode) {
if (_accessedByClosureIn == null) {
_accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>();
}
Map<VariableElement, List<Node>> accessMap =
_accessedByClosureIn.putIfAbsent(
contextNode, () => new Maplet<VariableElement, List<Node>>());
accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode);
}
String toString() => 'TreeElementMapping($analyzedElement)';
@override
void forEachConstantNode(f(Node n, ConstantExpression c)) {
if (_constants != null) {
_constants.forEach(f);
}
}
@override
Element getFunctionDefinition(FunctionExpression node) {
return this[node];
}
@override
ConstructorElement getRedirectingTargetConstructor(
RedirectingFactoryBody node) {
return this[node];
}
void defineTarget(Node node, JumpTarget target) {
if (_definedTargets == null) {
_definedTargets = new Maplet<Node, JumpTarget>();
}
_definedTargets[node] = target;
}
void undefineTarget(Node node) {
if (_definedTargets != null) {
_definedTargets.remove(node);
if (_definedTargets.isEmpty) {
_definedTargets = null;
}
}
}
@override
JumpTarget getTargetDefinition(Node node) {
return _definedTargets != null ? _definedTargets[node] : null;
}
void registerTargetOf(GotoStatement node, JumpTarget target) {
if (_usedTargets == null) {
_usedTargets = new Maplet<GotoStatement, JumpTarget>();
}
_usedTargets[node] = target;
}
@override
JumpTarget getTargetOf(GotoStatement node) {
return _usedTargets != null ? _usedTargets[node] : null;
}
void defineLabel(Label label, LabelDefinition target) {
if (_definedLabels == null) {
_definedLabels = new Maplet<Label, LabelDefinition>();
}
_definedLabels[label] = target;
}
void undefineLabel(Label label) {
if (_definedLabels != null) {
_definedLabels.remove(label);
if (_definedLabels.isEmpty) {
_definedLabels = null;
}
}
}
@override
LabelDefinition getLabelDefinition(Label label) {
return _definedLabels != null ? _definedLabels[label] : null;
}
void registerTargetLabel(GotoStatement node, LabelDefinition label) {
assert(node.target != null);
if (_targetLabels == null) {
_targetLabels = new Maplet<GotoStatement, LabelDefinition>();
}
_targetLabels[node] = label;
}
@override
LabelDefinition getTargetLabel(GotoStatement node) {
assert(node.target != null);
return _targetLabels != null ? _targetLabels[node] : null;
}
void registerNativeData(Node node, dynamic nativeData) {
if (_nativeData == null) {
_nativeData = <Node, dynamic>{};
}
_nativeData[node] = nativeData;
}
@override
dynamic getNativeData(Node node) {
return _nativeData != null ? _nativeData[node] : null;
}
}