Further splitting of inference type-info

R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2963983002 .
This commit is contained in:
Johnni Winther 2017-06-30 09:52:15 +02:00
parent 469335dfb6
commit ee04f3dc5f
6 changed files with 330 additions and 158 deletions

View file

@ -87,7 +87,9 @@ class ElementGraphBuilder extends ast.Visitor<TypeInformation>
: this.analyzedElement = analyzedElement,
this.inferrer = inferrer,
this.types = inferrer.types,
this.inTreeData = inferrer.dataOf(analyzedElement) {
this.inTreeData = analyzedElement.isLocal
? inferrer.dataOfLocalFunction(analyzedElement)
: inferrer.dataOfMember(analyzedElement) {
assert(outermostElement != null);
if (locals != null) return;
ast.Node node;
@ -1115,7 +1117,7 @@ class ElementGraphBuilder extends ast.Visitor<TypeInformation>
});
return inferrer.concreteTypes.putIfAbsent(node, () {
return types.allocateClosure(node, element);
return types.allocateClosureForLocalFunction(node, element);
});
}
@ -1124,7 +1126,7 @@ class ElementGraphBuilder extends ast.Visitor<TypeInformation>
elements.getFunctionDefinition(node.function);
TypeInformation type =
inferrer.concreteTypes.putIfAbsent(node.function, () {
return types.allocateClosure(node.function, element);
return types.allocateClosureForLocalFunction(node.function, element);
});
locals.update(element, type, node);
visit(node.function);
@ -2735,7 +2737,12 @@ class ElementGraphBuilder extends ast.Visitor<TypeInformation>
mask = receiverType == types.dynamicType
? null
: types.newTypedSelector(receiverType, mask);
inferrer.updateSelectorInTree(analyzedElement, node, selector, mask);
if (analyzedElement.isLocal) {
inferrer.updateSelectorInLocalFunction(
analyzedElement, node, selector, mask);
} else {
inferrer.updateSelectorInMember(analyzedElement, node, selector, mask);
}
}
// If the receiver of the call is a local, we may know more about

View file

@ -110,8 +110,15 @@ class InferrerEngine {
}
}
GlobalTypeInferenceElementData dataOfLocalFunction(
LocalFunctionElement element) =>
_dataOf(element);
// TODO(johnniwinther): Make this private again.
GlobalTypeInferenceElementData dataOf(AstElement element) => inTreeData
GlobalTypeInferenceElementData dataOfMember(MemberElement element) =>
_dataOf(element);
GlobalTypeInferenceElementData _dataOf(AstElement element) => inTreeData
.putIfAbsent(element, () => new GlobalTypeInferenceElementData());
/**
@ -191,11 +198,22 @@ class InferrerEngine {
return returnType;
}
// TODO(johnniwinther): Pass the [ResolvedAst] instead of [owner].
void updateSelectorInTree(
AstElement owner, Spannable node, Selector selector, TypeMask mask) {
@deprecated
void updateSelectorInLocalFunction(LocalFunctionElement owner, Spannable node,
Selector selector, TypeMask mask) {
GlobalTypeInferenceElementData data = dataOfLocalFunction(owner);
_updateSelectorInTree(data, node, selector, mask);
}
void updateSelectorInMember(
MemberElement owner, Spannable node, Selector selector, TypeMask mask) {
GlobalTypeInferenceElementData data = dataOfMember(owner);
_updateSelectorInTree(data, node, selector, mask);
}
void _updateSelectorInTree(GlobalTypeInferenceElementData data,
Spannable node, Selector selector, TypeMask mask) {
ast.Node astNode = node;
GlobalTypeInferenceElementData data = dataOf(owner);
if (astNode.asSendSet() != null) {
if (selector.isSetter || selector.isIndexSet) {
data.setTypeMask(node, mask);
@ -387,7 +405,7 @@ class InferrerEngine {
}
if (info is ClosureTypeInformation) {
Iterable<FunctionElement> elements = [info.element];
Iterable<FunctionElement> elements = [info.closure];
trace(elements, new ClosureTracerVisitor(elements, info, this));
} else if (info is CallSiteTypeInformation) {
if (info is StaticCallSiteTypeInformation &&
@ -409,10 +427,12 @@ class InferrerEngine {
info.callees.where((e) => e.isFunction));
trace(elements, new ClosureTracerVisitor(elements, info, this));
}
} else {
assert(info is ElementTypeInformation);
trace([info.element],
new StaticTearOffClosureTracerVisitor(info.element, info, this));
} else if (info is MemberTypeInformation) {
trace([info.member],
new StaticTearOffClosureTracerVisitor(info.member, info, this));
} else if (info is ParameterTypeInformation) {
throw new SpannableAssertionFailure(
NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info');
}
});
@ -451,15 +471,16 @@ class InferrerEngine {
});
types.allocatedClosures.forEach((TypeInformation info) {
if (info is ElementTypeInformation) {
print('${types.getInferredSignatureOf(info.element)} for '
'${info.element}');
print('${info.getInferredSignature(types)} for '
'${info.debugName}');
} else if (info is ClosureTypeInformation) {
print('${types.getInferredSignatureOf(info.element)} for '
'${info.element}');
print('${info.getInferredSignature(types)} for '
'${info.debugName}');
} else if (info is DynamicCallSiteTypeInformation) {
for (MemberElement target in info.targets) {
if (target is MethodElement) {
print('${types.getInferredSignatureOf(target)} for ${target}');
print(
'${types.getInferredSignatureOfMethod(target)} for ${target}');
} else {
print(
'${types.getInferredTypeOfMember(target).type} for ${target}');
@ -468,7 +489,7 @@ class InferrerEngine {
} else if (info is StaticCallSiteTypeInformation) {
ClassElement cls = info.calledElement.enclosingClass;
FunctionElement callMethod = cls.lookupMember(Identifiers.call);
print('${types.getInferredSignatureOf(callMethod)} for ${cls}');
print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}');
} else {
print('${info.type} for some unknown kind of closure');
}
@ -519,7 +540,7 @@ class InferrerEngine {
if (value.isFunction) {
FunctionConstantValue functionConstant = value;
MethodElement function = functionConstant.element;
type = types.allocateClosure(node, function);
type = types.allocateClosureForMethod(node, function);
} else {
// Although we might find a better type, we have to keep
// the old type around to ensure that we get a complete view
@ -906,8 +927,16 @@ class InferrerEngine {
ArgumentsTypes arguments,
SideEffects sideEffects,
bool inLoop) {
return _registerCalledElement(
node, selector, mask, caller, callee, arguments, sideEffects, inLoop);
CallSiteTypeInformation info = new LocalFunctionCallSiteTypeInformation(
types.currentMember,
node,
caller,
callee,
selector,
mask,
arguments,
inLoop);
return _registerCalledElement(info, selector, callee, sideEffects);
}
/**
@ -929,8 +958,16 @@ class InferrerEngine {
ArgumentsTypes arguments,
SideEffects sideEffects,
bool inLoop) {
return _registerCalledElement(
node, selector, mask, caller, callee, arguments, sideEffects, inLoop);
CallSiteTypeInformation info = new StaticCallSiteTypeInformation(
types.currentMember,
node,
caller,
callee,
selector,
mask,
arguments,
inLoop);
return _registerCalledElement(info, selector, callee, sideEffects);
}
/**
@ -943,24 +980,8 @@ class InferrerEngine {
*
* [inLoop] tells whether the call happens in a loop.
*/
TypeInformation _registerCalledElement(
Spannable node,
Selector selector,
TypeMask mask,
Element caller,
Element callee,
ArgumentsTypes arguments,
SideEffects sideEffects,
bool inLoop) {
CallSiteTypeInformation info = new StaticCallSiteTypeInformation(
types.currentMember,
node,
caller,
callee,
selector,
mask,
arguments,
inLoop);
TypeInformation _registerCalledElement(CallSiteTypeInformation info,
Selector selector, Element callee, SideEffects sideEffects) {
// If this class has a 'call' method then we have essentially created a
// closure here. Register it as such so that it is traced.
// Note: we exclude factory constructors because they don't always create an

View file

@ -303,7 +303,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
void bailoutIfReaches(bool predicate(ParameterElement e)) {
for (var user in currentUser.users) {
if (user is ParameterTypeInformation) {
if (predicate(user.element)) {
if (predicate(user.parameter)) {
bailout('Reached suppressed parameter without precise receiver');
break;
}
@ -452,28 +452,28 @@ abstract class TracerVisitor implements TypeInformationVisitor {
if (info.isClosurized) {
bailout('Returned from a closurized method');
}
if (isClosure(info.element)) {
if (isClosure(info.member)) {
bailout('Returned from a closure');
}
if (info.element.isField &&
if (info.member.isField &&
!inferrer.compiler.backend.canFieldBeUsedForGlobalOptimizations(
info.element, inferrer.closedWorld)) {
info.member, inferrer.closedWorld)) {
bailout('Escape to code that has special backend treatment');
}
addNewEscapeInformation(info);
}
void visitParameterTypeInformation(ParameterTypeInformation info) {
if (inferrer.isNativeMember(info.declaration)) {
if (inferrer.isNativeMember(info.method)) {
bailout('Passed to a native method');
}
if (!inferrer.compiler.backend
.canFunctionParametersBeUsedForGlobalOptimizations(
info.declaration, inferrer.closedWorld)) {
info.method, inferrer.closedWorld)) {
bailout('Escape to code that has special backend treatment');
}
if (isParameterOfListAddingMethod(info.element) ||
isParameterOfMapAddingMethod(info.element)) {
if (isParameterOfListAddingMethod(info.parameter) ||
isParameterOfMapAddingMethod(info.parameter)) {
// These elements are being handled in
// [visitDynamicCallSiteTypeInformation].
return;

View file

@ -408,11 +408,11 @@ class _GraphGenerator extends TypeInformationVisitor {
}
void visitMemberTypeInformation(MemberTypeInformation info) {
addNode(info, 'Member\n${info.element}');
addNode(info, 'Member\n${info.debugName}');
}
void visitParameterTypeInformation(ParameterTypeInformation info) {
addNode(info, 'Parameter ${info.element?.name ?? ''}');
addNode(info, 'Parameter ${info.debugName}');
}
void visitClosureTypeInformation(ClosureTypeInformation info) {

View file

@ -63,7 +63,7 @@ abstract class TypeInformation {
final MemberTypeInformation context;
/// The element this [TypeInformation] node belongs to.
TypedElement get contextMember => context == null ? null : context.element;
TypedElement get contextMember => context == null ? null : context.member;
Iterable<TypeInformation> get assignments => _assignments;
@ -206,7 +206,7 @@ abstract class TypeInformation {
/// The [Element] where this [TypeInformation] was created. May be `null`
/// for some [TypeInformation] nodes, where we do not need to store
/// the information.
Element get owner => (context != null) ? context.element : null;
TypedElement get owner => (context != null) ? context.member : null;
/// Returns whether the type cannot change after it has been
/// inferred.
@ -343,7 +343,7 @@ class ParameterAssignments extends IterableBase<TypeInformation> {
*
*/
abstract class ElementTypeInformation extends TypeInformation {
final Element element;
final Element _element;
/// Marker to disable inference for closures in [handleSpecialCases].
bool disableInferenceForClosures = true;
@ -360,14 +360,18 @@ abstract class ElementTypeInformation extends TypeInformation {
} else if (element.isLocal) {
return new MemberTypeInformation._localFunction(element);
}
return new MemberTypeInformation._member(element);
return new MemberTypeInformation._forMember(element);
}
ElementTypeInformation._internal(MemberTypeInformation context, this.element)
ElementTypeInformation._internal(MemberTypeInformation context, this._element)
: super(context);
ElementTypeInformation._withAssignments(
MemberTypeInformation context, this.element, assignments)
MemberTypeInformation context, this._element, assignments)
: super.withAssignments(context, assignments);
String getInferredSignature(TypeSystem types);
String get debugName;
}
/**
@ -383,7 +387,7 @@ abstract class ElementTypeInformation extends TypeInformation {
*/
class MemberTypeInformation extends ElementTypeInformation
with ApplyableTypeInformation {
TypedElement get element => super.element;
TypedElement get _member => super._element;
/**
* If [element] is a function, [closurizedCount] is the number of
@ -410,19 +414,41 @@ class MemberTypeInformation extends ElementTypeInformation
MemberTypeInformation._internal(Element element)
: super._internal(null, element);
MemberTypeInformation._member(MemberElement element)
MemberTypeInformation._forMember(MemberElement element)
: this._internal(element);
MemberTypeInformation._localFunction(LocalFunctionElement element)
: this._internal(element);
void addCall(Element caller, Spannable node) {
TypedElement get member => _element;
String get debugName => '$member';
void addCallFromMember(MemberElement caller, Spannable node) {
_addCall(caller, node);
}
@deprecated
void addCallFromLocalFunction(LocalFunctionElement caller, Spannable node) {
_addCall(caller, node);
}
void _addCall(Element caller, Spannable node) {
assert(node is ast.Node || node is Element);
_callers ??= <Element, Setlet<Spannable>>{};
_callers.putIfAbsent(caller, () => new Setlet()).add(node);
}
void removeCall(Element caller, node) {
void removeCallFromMember(MemberElement caller, node) {
_removeCall(caller, node);
}
@deprecated
void removeCallFromLocalFunction(LocalFunctionElement caller, node) {
_removeCall(caller, node);
}
void _removeCall(Element caller, node) {
if (_callers == null) return;
Setlet calls = _callers[caller];
if (calls == null) return;
@ -470,33 +496,33 @@ class MemberTypeInformation extends ElementTypeInformation
bool get isStable => super.isStable && !isClosurized;
TypeMask handleSpecialCases(InferrerEngine inferrer) {
if (element.isField &&
if (_member.isField &&
(!inferrer.backend.canFieldBeUsedForGlobalOptimizations(
element, inferrer.closedWorld) ||
inferrer.assumeDynamic(element))) {
_member, inferrer.closedWorld) ||
inferrer.assumeDynamic(_member))) {
// Do not infer types for fields that have a corresponding annotation or
// are assigned by synthesized calls
giveUp(inferrer);
return safeType(inferrer);
}
if (inferrer.isNativeMember(element)) {
if (inferrer.isNativeMember(_member)) {
// Use the type annotation as the type for native elements. We
// also give up on inferring to make sure this element never
// goes in the work queue.
giveUp(inferrer);
if (element.isField) {
FieldElement field = element;
if (_member.isField) {
FieldElement field = _member;
return inferrer
.typeOfNativeBehavior(inferrer.closedWorld.nativeData
.getNativeFieldLoadBehavior(field))
.type;
} else {
assert(element.isFunction ||
element.isGetter ||
element.isSetter ||
element.isConstructor);
MethodElement methodElement = element;
assert(_member.isFunction ||
_member.isGetter ||
_member.isSetter ||
_member.isConstructor);
MethodElement methodElement = _member;
var elementType = methodElement.type;
if (elementType.kind != ResolutionTypeKind.FUNCTION) {
return safeType(inferrer);
@ -510,8 +536,8 @@ class MemberTypeInformation extends ElementTypeInformation
}
CommonMasks commonMasks = inferrer.commonMasks;
if (element.isConstructor) {
ConstructorElement constructor = element;
if (_member.isConstructor) {
ConstructorElement constructor = _member;
if (constructor.isIntFromEnvironmentConstructor) {
giveUp(inferrer);
return commonMasks.intType.nullable();
@ -530,19 +556,19 @@ class MemberTypeInformation extends ElementTypeInformation
Compiler compiler = inferrer.compiler;
if (!compiler.options.trustTypeAnnotations &&
!compiler.options.enableTypeAssertions &&
!inferrer.trustTypeAnnotations(element)) {
!inferrer.trustTypeAnnotations(_member)) {
return mask;
}
if (element.isGenerativeConstructor || element.isSetter) {
if (_member.isGenerativeConstructor || _member.isSetter) {
return mask;
}
if (element.isField) {
return _narrowType(inferrer.closedWorld, mask, element.type);
if (_member.isField) {
return _narrowType(inferrer.closedWorld, mask, _member.type);
}
assert(
element.isFunction || element.isGetter || element.isFactoryConstructor);
_member.isFunction || _member.isGetter || _member.isFactoryConstructor);
ResolutionFunctionType type = element.type;
ResolutionFunctionType type = _member.type;
return _narrowType(inferrer.closedWorld, mask, type.returnType);
}
@ -557,7 +583,7 @@ class MemberTypeInformation extends ElementTypeInformation
return potentiallyNarrowType(super.safeType(inferrer), inferrer);
}
String toString() => 'MemberElement $element $type';
String toString() => 'MemberElement $_member $type';
accept(TypeInformationVisitor visitor) {
return visitor.visitMemberTypeInformation(this);
@ -566,11 +592,11 @@ class MemberTypeInformation extends ElementTypeInformation
bool hasStableType(InferrerEngine inferrer) {
// The number of assignments of non-final fields is
// not stable. Therefore such a field cannot be stable.
if (element.isField && !(element.isConst || element.isFinal)) {
if (_member.isField && !(_member.isConst || _member.isFinal)) {
return false;
}
if (element.isFunction) return false;
if (_member.isFunction) return false;
return super.hasStableType(inferrer);
}
@ -582,6 +608,15 @@ class MemberTypeInformation extends ElementTypeInformation
_callers = null;
super.cleanup();
}
@override
String getInferredSignature(TypeSystem types) {
if (_member.isLocal) {
return types.getInferredSignatureOfLocalFunction(_member);
} else {
return types.getInferredSignatureOfMethod(_member);
}
}
}
/**
@ -594,31 +629,39 @@ class MemberTypeInformation extends ElementTypeInformation
* the [ElementTypeInformation] factory.
*/
class ParameterTypeInformation extends ElementTypeInformation {
ParameterElement get element => super.element;
FunctionElement get declaration => element.functionDeclaration;
ParameterElement get _parameter => super._element;
final FunctionElement _declaration;
// TODO(johnniwinther): This should be a [MethodElement].
final FunctionElement _method;
ParameterTypeInformation._internal(
MemberTypeInformation context, ParameterElement parameter)
ParameterTypeInformation._internal(MemberTypeInformation context,
ParameterElement parameter, this._declaration, this._method)
: super._internal(context, parameter);
factory ParameterTypeInformation._static(
ParameterElement element, TypeSystem types) {
assert(!element.functionDeclaration.isInstanceMember);
MethodElement method = element.functionDeclaration;
assert(!method.isInstanceMember);
return new ParameterTypeInformation._internal(
types.getInferredTypeOfMember(method), element);
types.getInferredTypeOfMember(method), element, method, method);
}
factory ParameterTypeInformation._localFunction(
ParameterElement element, TypeSystem types) {
LocalFunctionElement localFunction = element.functionDeclaration;
return new ParameterTypeInformation._internal(
types.getInferredTypeOfLocalFunction(localFunction), element);
types.getInferredTypeOfLocalFunction(localFunction),
element,
localFunction,
// TODO(johnniwinther): This should be `localFunction.callMethod`.
localFunction);
}
ParameterTypeInformation._instanceMember(
ParameterElement element, TypeSystem types)
: super._withAssignments(
: _declaration = element.functionDeclaration,
_method = element.functionDeclaration,
super._withAssignments(
types.getInferredTypeOfMember(
element.functionDeclaration as MethodElement),
element,
@ -626,22 +669,30 @@ class ParameterTypeInformation extends ElementTypeInformation {
assert(element.functionDeclaration.isInstanceMember);
}
// TODO(johnniwinther): This should be a [MethodElement].
FunctionElement get method => _method;
Local get parameter => _parameter;
String get debugName => '$parameter';
bool isTearOffClosureParameter = false;
void tagAsTearOffClosureParameter(InferrerEngine inferrer) {
assert(element.isRegularParameter);
assert(_parameter.isRegularParameter);
isTearOffClosureParameter = true;
// We have to add a flow-edge for the default value (if it exists), as we
// might not see all call-sites and thus miss the use of it.
TypeInformation defaultType = inferrer.getDefaultTypeOfParameter(element);
TypeInformation defaultType =
inferrer.getDefaultTypeOfParameter(_parameter);
if (defaultType != null) defaultType.addUser(this);
}
// TODO(herhut): Cleanup into one conditional.
TypeMask handleSpecialCases(InferrerEngine inferrer) {
if (!inferrer.backend.canFunctionParametersBeUsedForGlobalOptimizations(
element.functionDeclaration, inferrer.closedWorld) ||
inferrer.assumeDynamic(declaration)) {
_method, inferrer.closedWorld) ||
inferrer.assumeDynamic(_method)) {
// Do not infer types for parameters that have a corresponding annotation
// or that are assigned by synthesized calls.
giveUp(inferrer);
@ -650,9 +701,9 @@ class ParameterTypeInformation extends ElementTypeInformation {
// The below do not apply to parameters of constructors, so skip
// initializing formals.
if (element.isInitializingFormal) return null;
if (_parameter.isInitializingFormal) return null;
if ((isTearOffClosureParameter || declaration.isLocal) &&
if ((isTearOffClosureParameter || _declaration.isLocal) &&
disableInferenceForClosures) {
// Do not infer types for parameters of closures. We do not
// clear the assignments in case the closure is successfully
@ -660,9 +711,9 @@ class ParameterTypeInformation extends ElementTypeInformation {
giveUp(inferrer, clearAssignments: false);
return safeType(inferrer);
}
if (declaration.isInstanceMember &&
(declaration.name == Identifiers.noSuchMethod_ ||
(declaration.name == Identifiers.call &&
if (_declaration.isInstanceMember &&
(_declaration.name == Identifiers.noSuchMethod_ ||
(_declaration.name == Identifiers.call &&
disableInferenceForClosures))) {
// Do not infer types for parameters of [noSuchMethod] and
// [call] instance methods.
@ -670,11 +721,11 @@ class ParameterTypeInformation extends ElementTypeInformation {
return safeType(inferrer);
}
if (inferrer.closedWorldRefiner
.getCurrentlyKnownMightBePassedToApply(declaration)) {
.getCurrentlyKnownMightBePassedToApply(_method)) {
giveUp(inferrer);
return safeType(inferrer);
}
if (declaration == inferrer.mainElement) {
if (_method == inferrer.mainElement) {
// The implicit call to main is not seen by the inferrer,
// therefore we explicitly set the type of its parameters as
// dynamic.
@ -690,14 +741,14 @@ class ParameterTypeInformation extends ElementTypeInformation {
TypeMask potentiallyNarrowType(TypeMask mask, InferrerEngine inferrer) {
Compiler compiler = inferrer.compiler;
if (!compiler.options.trustTypeAnnotations &&
!inferrer.trustTypeAnnotations(declaration)) {
!inferrer.trustTypeAnnotations(_method)) {
return mask;
}
// When type assertions are enabled (aka checked mode), we have to always
// ignore type annotations to ensure that the checks are actually inserted
// into the function body and retained until runtime.
assert(!compiler.options.enableTypeAssertions);
return _narrowType(inferrer.closedWorld, mask, element.type);
return _narrowType(inferrer.closedWorld, mask, _parameter.type);
}
TypeMask computeType(InferrerEngine inferrer) {
@ -714,7 +765,7 @@ class ParameterTypeInformation extends ElementTypeInformation {
bool hasStableType(InferrerEngine inferrer) {
// The number of assignments of parameters of instance methods is
// not stable. Therefore such a parameter cannot be stable.
if (element.functionDeclaration.isInstanceMember) {
if (_declaration.isInstanceMember) {
return false;
}
return super.hasStableType(inferrer);
@ -724,7 +775,12 @@ class ParameterTypeInformation extends ElementTypeInformation {
return visitor.visitParameterTypeInformation(this);
}
String toString() => 'ParameterElement $element $type';
String toString() => 'ParameterElement $_parameter $type';
@override
String getInferredSignature(TypeSystem types) {
throw new UnsupportedError('ParameterTypeInformation.getInferredSignature');
}
}
/**
@ -740,7 +796,8 @@ class ParameterTypeInformation extends ElementTypeInformation {
abstract class CallSiteTypeInformation extends TypeInformation
with ApplyableTypeInformation {
final Spannable call;
final Element caller;
// TODO(johnniwinther): [caller] should always be a [MemberElement].
final /*LocalFunctionElement|MemberElement*/ Element caller;
final Selector selector;
final TypeMask mask;
final ArgumentsTypes arguments;
@ -763,6 +820,18 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
final Element calledElement;
StaticCallSiteTypeInformation(
MemberTypeInformation context,
Spannable call,
Element enclosing,
MemberElement calledElement,
Selector selector,
TypeMask mask,
ArgumentsTypes arguments,
bool inLoop)
: this.internal(context, call, enclosing, calledElement, selector, mask,
arguments, inLoop);
StaticCallSiteTypeInformation.internal(
MemberTypeInformation context,
Spannable call,
Element enclosing,
@ -773,14 +842,17 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
bool inLoop)
: super(context, call, enclosing, selector, mask, arguments, inLoop);
MemberTypeInformation _getCalledTypeInfo(InferrerEngine inferrer) {
return inferrer.types.getInferredTypeOfMember(calledElement);
}
void addToGraph(InferrerEngine inferrer) {
MemberTypeInformation callee;
if (calledElement.isLocal) {
callee = inferrer.types.getInferredTypeOfLocalFunction(calledElement);
MemberTypeInformation callee = _getCalledTypeInfo(inferrer);
if (caller.isLocal) {
callee.addCallFromLocalFunction(caller, call);
} else {
callee = inferrer.types.getInferredTypeOfMember(calledElement);
callee.addCallFromMember(caller, call);
}
callee.addCall(caller, call);
callee.addUser(this);
if (arguments != null) {
arguments.forEach((info) => info.addUser(this));
@ -798,24 +870,16 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
return selector == null;
}
TypeInformation _getCalledTypeInfoWithSelector(InferrerEngine inferrer) {
return inferrer.typeOfMemberWithSelector(calledElement, selector);
}
TypeMask computeType(InferrerEngine inferrer) {
if (isSynthesized) {
assert(arguments != null);
if (calledElement.isLocal) {
return inferrer.types
.getInferredTypeOfLocalFunction(calledElement)
.type;
} else {
return inferrer.types.getInferredTypeOfMember(calledElement).type;
}
return _getCalledTypeInfo(inferrer).type;
} else {
if (calledElement.isLocal) {
return inferrer
.typeOfLocalFunctionWithSelector(calledElement, selector)
.type;
} else {
return inferrer.typeOfMemberWithSelector(calledElement, selector).type;
}
return _getCalledTypeInfoWithSelector(inferrer).type;
}
}
@ -826,25 +890,14 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
}
bool hasStableType(InferrerEngine inferrer) {
bool isStable;
if (calledElement.isLocal) {
isStable =
inferrer.types.getInferredTypeOfLocalFunction(calledElement).isStable;
} else {
isStable = inferrer.types.getInferredTypeOfMember(calledElement).isStable;
}
bool isStable = _getCalledTypeInfo(inferrer).isStable;
return isStable &&
(arguments == null || arguments.every((info) => info.isStable)) &&
super.hasStableType(inferrer);
}
void removeAndClearReferences(InferrerEngine inferrer) {
ElementTypeInformation callee;
if (calledElement.isLocal) {
callee = inferrer.types.getInferredTypeOfLocalFunction(calledElement);
} else {
callee = inferrer.types.getInferredTypeOfMember(calledElement);
}
ElementTypeInformation callee = _getCalledTypeInfo(inferrer);
callee.removeUser(this);
if (arguments != null) {
arguments.forEach((info) => info.removeUser(this));
@ -853,6 +906,30 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
}
}
@deprecated
class LocalFunctionCallSiteTypeInformation
extends StaticCallSiteTypeInformation {
LocalFunctionCallSiteTypeInformation(
MemberTypeInformation context,
Spannable call,
Element enclosing,
LocalFunctionElement calledElement,
Selector selector,
TypeMask mask,
ArgumentsTypes arguments,
bool inLoop)
: super.internal(context, call, enclosing, calledElement, selector, mask,
arguments, inLoop);
MemberTypeInformation _getCalledTypeInfo(InferrerEngine inferrer) {
return inferrer.types.getInferredTypeOfLocalFunction(calledElement);
}
TypeInformation _getCalledTypeInfoWithSelector(InferrerEngine inferrer) {
return inferrer.typeOfLocalFunctionWithSelector(calledElement, selector);
}
}
class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
final TypeInformation receiver;
@ -881,7 +958,11 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
for (MemberElement element in targets) {
MemberTypeInformation callee =
inferrer.types.getInferredTypeOfMember(element);
callee.addCall(caller, call);
if (caller.isLocal) {
callee.addCallFromLocalFunction(caller, call);
} else {
callee.addCallFromMember(caller, call);
}
callee.addUser(this);
inferrer.updateParameterAssignments(
this, element, arguments, selector, typeMask,
@ -1028,7 +1109,11 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
TypeMask computeType(InferrerEngine inferrer) {
Iterable<MemberEntity> oldTargets = targets;
TypeMask typeMask = computeTypedSelector(inferrer);
inferrer.updateSelectorInTree(caller, call, selector, typeMask);
if (caller.isLocal) {
inferrer.updateSelectorInLocalFunction(caller, call, selector, typeMask);
} else {
inferrer.updateSelectorInMember(caller, call, selector, typeMask);
}
TypeMask maskToUse =
inferrer.closedWorld.extendMaskIfReachesAll(selector, typeMask);
@ -1053,7 +1138,11 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
MemberElement element = _element;
MemberTypeInformation callee =
inferrer.types.getInferredTypeOfMember(element);
callee.addCall(caller, call);
if (caller.isLocal) {
callee.addCallFromLocalFunction(caller, call);
} else {
callee.addCallFromMember(caller, call);
}
callee.addUser(this);
inferrer.updateParameterAssignments(
this, element, arguments, selector, typeMask,
@ -1067,7 +1156,11 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
MemberElement element = _element;
MemberTypeInformation callee =
inferrer.types.getInferredTypeOfMember(element);
callee.removeCall(caller, call);
if (caller.isLocal) {
callee.removeCallFromLocalFunction(caller, call);
} else {
callee.removeCallFromMember(caller, call);
}
callee.removeUser(this);
inferrer.updateParameterAssignments(
this, element, arguments, selector, typeMask,
@ -1137,14 +1230,22 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
void giveUp(InferrerEngine inferrer, {bool clearAssignments: true}) {
if (!abandonInferencing) {
inferrer.updateSelectorInTree(caller, call, selector, mask);
if (caller.isLocal) {
inferrer.updateSelectorInLocalFunction(caller, call, selector, mask);
} else {
inferrer.updateSelectorInMember(caller, call, selector, mask);
}
Iterable<MemberEntity> oldTargets = targets;
targets = inferrer.closedWorld.locateMembers(selector, mask);
for (MemberElement element in targets) {
if (!oldTargets.contains(element)) {
MemberTypeInformation callee =
inferrer.types.getInferredTypeOfMember(element);
callee.addCall(caller, call);
if (caller.isLocal) {
callee.addCallFromLocalFunction(caller, call);
} else {
callee.addCallFromMember(caller, call);
}
inferrer.updateParameterAssignments(
this, element, arguments, selector, mask,
remove: false, addToQueue: true);
@ -1694,18 +1795,29 @@ class PhiElementTypeInformation extends TypeInformation {
class ClosureTypeInformation extends TypeInformation
with ApplyableTypeInformation {
final ast.Node node;
final Element element;
final Element _element;
ClosureTypeInformation(MemberTypeInformation context, this.node, this.element)
ClosureTypeInformation(
MemberTypeInformation context, ast.Node node, MethodElement element)
: this._internal(context, node, element);
ClosureTypeInformation._internal(
MemberTypeInformation context, this.node, this._element)
: super(context);
// TODO(johnniwinther): Type this as `FunctionEntity` when
// 'LocalFunctionElement.callMethod' is used as key for
Entity get closure => _element;
TypeMask computeType(InferrerEngine inferrer) => safeType(inferrer);
TypeMask safeType(InferrerEngine inferrer) {
return inferrer.types.functionType.type;
}
String toString() => 'Closure $element';
String get debugName => '$closure';
String toString() => 'Closure $_element';
accept(TypeInformationVisitor visitor) {
return visitor.visitClosureTypeInformation(this);
@ -1714,6 +1826,21 @@ class ClosureTypeInformation extends TypeInformation
bool hasStableType(InferrerEngine inferrer) {
return false;
}
String getInferredSignature(TypeSystem types) {
return types.getInferredSignatureOfMethod(_element);
}
}
@deprecated
class LocalFunctionClosureTypeInformation extends ClosureTypeInformation {
LocalFunctionClosureTypeInformation(MemberTypeInformation context,
ast.Node node, LocalFunctionElement element)
: super._internal(context, node, element);
String getInferredSignature(TypeSystem types) {
return types.getInferredSignatureOfLocalFunction(_element);
}
}
/**

View file

@ -353,13 +353,17 @@ class TypeSystem {
});
}
String getInferredSignatureOf(FunctionElement function) {
ElementTypeInformation info;
if (function.isLocal) {
info = getInferredTypeOfLocalFunction(function);
} else {
info = getInferredTypeOfMember(function as MethodElement);
}
String getInferredSignatureOfLocalFunction(LocalFunctionElement function) {
return _getInferredSignatureOf(
getInferredTypeOfLocalFunction(function), function);
}
String getInferredSignatureOfMethod(MethodElement function) {
return _getInferredSignatureOf(getInferredTypeOfMember(function), function);
}
String _getInferredSignatureOf(
ElementTypeInformation info, FunctionElement function) {
FunctionElement impl = function.implementation;
FunctionSignature signature = impl.functionSignature;
var res = "";
@ -420,7 +424,20 @@ class TypeSystem {
new ListTypeInformation(currentMember, mask, element, length);
}
TypeInformation allocateClosure(ast.Node node, Element element) {
/// Creates a [TypeInformation] object for the local function [element] of
/// a function expression or local function declaration used as a closure.
TypeInformation allocateClosureForLocalFunction(
ast.Node node, LocalFunctionElement element) {
TypeInformation result =
new LocalFunctionClosureTypeInformation(currentMember, node, element);
allocatedClosures.add(result);
return result;
}
/// Creates a [TypeInformation] object for the closurization of a static or
/// top-level method [element] used a function constant.
TypeInformation allocateClosureForMethod(
ast.Node node, MethodElement element) {
TypeInformation result =
new ClosureTypeInformation(currentMember, node, element);
allocatedClosures.add(result);