mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Update RTI optimization to handle type literal uses
... for generic methods and local function. Also update capture conversion to recognize the new kinds of type variables. Change-Id: I9b8771b0ebe6c9e926712fa31b0bdea966cc6a25 Reviewed-on: https://dart-review.googlesource.com/34600 Reviewed-by: Sigmund Cherem <sigmund@google.com> Reviewed-by: Emily Fortuna <efortuna@google.com>
This commit is contained in:
parent
b2f8b5481d
commit
73e35eb035
|
@ -179,16 +179,18 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
|
|||
_customElementsResolutionAnalysis.registerTypeLiteral(type);
|
||||
if (type.isTypeVariable) {
|
||||
TypeVariableType typeVariable = type;
|
||||
if (typeVariable.element.typeDeclaration is ClassEntity) {
|
||||
// GENERIC_METHODS: The `is!` test above filters away method type
|
||||
// variables, because they have the value `dynamic` with the
|
||||
// incomplete support for generic methods offered with
|
||||
// '--generic-method-syntax'. This must be revised in order to
|
||||
// support generic methods fully.
|
||||
ClassEntity cls = typeVariable.element.typeDeclaration;
|
||||
_rtiNeedBuilder.registerClassUsingTypeVariableExpression(cls);
|
||||
registerImpact(_impacts.typeVariableExpression);
|
||||
Entity typeDeclaration = typeVariable.element.typeDeclaration;
|
||||
if (typeDeclaration is ClassEntity) {
|
||||
_rtiNeedBuilder
|
||||
.registerClassUsingTypeVariableLiteral(typeDeclaration);
|
||||
} else if (typeDeclaration is FunctionEntity) {
|
||||
_rtiNeedBuilder
|
||||
.registerMethodUsingTypeVariableLiteral(typeDeclaration);
|
||||
} else if (typeDeclaration is Local) {
|
||||
_rtiNeedBuilder.registerLocalFunctionUsingTypeVariableLiteral(
|
||||
typeDeclaration);
|
||||
}
|
||||
registerImpact(_impacts.typeVariableExpression);
|
||||
}
|
||||
hasTypeLiteral = true;
|
||||
break;
|
||||
|
|
|
@ -95,7 +95,7 @@ abstract class RuntimeTypesNeed {
|
|||
// TODO(redemption): Remove this when the old frontend is deleted.
|
||||
bool localFunctionNeedsSignature(Local localFunction);
|
||||
|
||||
bool classUsesTypeVariableExpression(ClassEntity cls);
|
||||
bool classUsesTypeVariableLiteral(ClassEntity cls);
|
||||
}
|
||||
|
||||
class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
|
||||
|
@ -105,7 +105,7 @@ class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
|
|||
bool classNeedsTypeArguments(ClassEntity cls) => true;
|
||||
|
||||
@override
|
||||
bool classUsesTypeVariableExpression(ClassEntity cls) => true;
|
||||
bool classUsesTypeVariableLiteral(ClassEntity cls) => true;
|
||||
|
||||
@override
|
||||
bool localFunctionNeedsSignature(Local localFunction) => true;
|
||||
|
@ -125,8 +125,15 @@ class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
|
|||
|
||||
/// Interface for computing classes and methods that need runtime types.
|
||||
abstract class RuntimeTypesNeedBuilder {
|
||||
/// Registers that [cls] contains a type variable literal.
|
||||
void registerClassUsingTypeVariableExpression(ClassEntity cls);
|
||||
/// Registers that [cls] uses one of its type variables as a literal.
|
||||
void registerClassUsingTypeVariableLiteral(ClassEntity cls);
|
||||
|
||||
/// Registers that [method] uses one of its type variables as a literal.
|
||||
void registerMethodUsingTypeVariableLiteral(FunctionEntity method);
|
||||
|
||||
/// Registers that [localFunction] uses one of its type variables as a
|
||||
/// literal.
|
||||
void registerLocalFunctionUsingTypeVariableLiteral(Local localFunction);
|
||||
|
||||
/// Registers that if [element] needs type arguments at runtime then so does
|
||||
/// [dependency].
|
||||
|
@ -163,7 +170,13 @@ class TrivialRuntimeTypesNeedBuilder implements RuntimeTypesNeedBuilder {
|
|||
const TrivialRuntimeTypesNeedBuilder();
|
||||
|
||||
@override
|
||||
void registerClassUsingTypeVariableExpression(ClassEntity cls) {}
|
||||
void registerClassUsingTypeVariableLiteral(ClassEntity cls) {}
|
||||
|
||||
@override
|
||||
void registerMethodUsingTypeVariableLiteral(FunctionEntity method) {}
|
||||
|
||||
@override
|
||||
void registerLocalFunctionUsingTypeVariableLiteral(Local localFunction) {}
|
||||
|
||||
@override
|
||||
RuntimeTypesNeed computeRuntimeTypesNeed(
|
||||
|
@ -526,9 +539,8 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
|||
final Set<Local> localFunctionsNeedingSignature;
|
||||
final Set<Local> localFunctionsNeedingTypeArguments;
|
||||
|
||||
/// The set of classes that use one of their type variables as expressions
|
||||
/// to get the runtime type.
|
||||
final Set<ClassEntity> classesUsingTypeVariableExpression;
|
||||
/// The set of classes that use one of their type variables as literals.
|
||||
final Set<ClassEntity> classesUsingTypeVariableLiterals;
|
||||
|
||||
RuntimeTypesNeedImpl(
|
||||
this._elementEnvironment,
|
||||
|
@ -538,7 +550,7 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
|||
this.methodsNeedingTypeArguments,
|
||||
this.localFunctionsNeedingSignature,
|
||||
this.localFunctionsNeedingTypeArguments,
|
||||
this.classesUsingTypeVariableExpression);
|
||||
this.classesUsingTypeVariableLiterals);
|
||||
|
||||
bool checkClass(covariant ClassEntity cls) => true;
|
||||
|
||||
|
@ -580,8 +592,8 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
|||
}
|
||||
|
||||
@override
|
||||
bool classUsesTypeVariableExpression(ClassEntity cls) {
|
||||
return classesUsingTypeVariableExpression.contains(cls);
|
||||
bool classUsesTypeVariableLiteral(ClassEntity cls) {
|
||||
return classesUsingTypeVariableLiterals.contains(cls);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,19 +601,19 @@ class _ResolutionRuntimeTypesNeed extends RuntimeTypesNeedImpl {
|
|||
_ResolutionRuntimeTypesNeed(
|
||||
ElementEnvironment elementEnvironment,
|
||||
BackendUsage backendUsage,
|
||||
Set<ClassEntity> classesNeedingRti,
|
||||
Set<FunctionEntity> methodsNeedingRti,
|
||||
Set<FunctionEntity> methodsNeedingGenericRti,
|
||||
Set<Local> localFunctionsNeedingRti,
|
||||
Set<ClassEntity> classesNeedingTypeArguments,
|
||||
Set<FunctionEntity> methodsNeedingSignature,
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments,
|
||||
Set<Local> localFunctionsNeedingSignature,
|
||||
Set<Local> localFunctionsNeedingTypeArguments,
|
||||
Set<ClassEntity> classesUsingTypeVariableExpression)
|
||||
: super(
|
||||
elementEnvironment,
|
||||
backendUsage,
|
||||
classesNeedingRti,
|
||||
methodsNeedingRti,
|
||||
methodsNeedingGenericRti,
|
||||
localFunctionsNeedingRti,
|
||||
classesNeedingTypeArguments,
|
||||
methodsNeedingSignature,
|
||||
methodsNeedingTypeArguments,
|
||||
localFunctionsNeedingSignature,
|
||||
localFunctionsNeedingTypeArguments,
|
||||
classesUsingTypeVariableExpression);
|
||||
|
||||
|
@ -615,9 +627,14 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
|||
final Map<Entity, Set<Entity>> typeArgumentDependencies =
|
||||
<Entity, Set<Entity>>{};
|
||||
|
||||
final Set<ClassEntity> classesUsingTypeVariableExpression =
|
||||
final Set<ClassEntity> classesUsingTypeVariableLiterals =
|
||||
new Set<ClassEntity>();
|
||||
|
||||
final Set<FunctionEntity> methodsUsingTypeVariableLiterals =
|
||||
new Set<FunctionEntity>();
|
||||
|
||||
final Set<Local> localFunctionsUsingTypeVariableLiterals = new Set<Local>();
|
||||
|
||||
final Set<ClassEntity> classesUsingTypeVariableTests = new Set<ClassEntity>();
|
||||
|
||||
Set<DartType> isChecks;
|
||||
|
@ -630,8 +647,18 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
|||
bool checkClass(covariant ClassEntity cls) => true;
|
||||
|
||||
@override
|
||||
void registerClassUsingTypeVariableExpression(ClassEntity cls) {
|
||||
classesUsingTypeVariableExpression.add(cls);
|
||||
void registerClassUsingTypeVariableLiteral(ClassEntity cls) {
|
||||
classesUsingTypeVariableLiterals.add(cls);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerMethodUsingTypeVariableLiteral(FunctionEntity method) {
|
||||
methodsUsingTypeVariableLiterals.add(method);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerLocalFunctionUsingTypeVariableLiteral(Local localFunction) {
|
||||
localFunctionsUsingTypeVariableLiterals.add(localFunction);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -771,9 +798,12 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
|||
checkClosures();
|
||||
}
|
||||
|
||||
// Add the classes that need RTI because they use a type variable as
|
||||
// expression.
|
||||
classesUsingTypeVariableExpression.forEach(potentiallyNeedTypeArguments);
|
||||
// Add the classes, methods and local functions that need type arguments
|
||||
// because they use a type variable as a literal.
|
||||
classesUsingTypeVariableLiterals.forEach(potentiallyNeedTypeArguments);
|
||||
methodsUsingTypeVariableLiterals.forEach(potentiallyNeedTypeArguments);
|
||||
localFunctionsUsingTypeVariableLiterals
|
||||
.forEach(potentiallyNeedTypeArguments);
|
||||
|
||||
return _createRuntimeTypesNeed(
|
||||
_elementEnvironment,
|
||||
|
@ -783,7 +813,7 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
|||
methodsNeedingTypeArguments,
|
||||
localFunctionsNeedingSignature,
|
||||
localFunctionsNeedingTypeArguments,
|
||||
classesUsingTypeVariableExpression);
|
||||
classesUsingTypeVariableLiterals);
|
||||
}
|
||||
|
||||
RuntimeTypesNeed _createRuntimeTypesNeed(
|
||||
|
|
|
@ -331,7 +331,7 @@ class RuntimeTypeGenerator {
|
|||
if (generated.contains(superclass)) return;
|
||||
|
||||
if (classesUsingTypeVariableTests.contains(superclass) ||
|
||||
_rtiNeed.classUsesTypeVariableExpression(superclass) ||
|
||||
_rtiNeed.classUsesTypeVariableLiteral(superclass) ||
|
||||
checkedClasses.contains(superclass)) {
|
||||
// Generate substitution. If no substitution is necessary, emit
|
||||
// `null` to overwrite a (possibly) existing substitution from the
|
||||
|
|
|
@ -42,9 +42,8 @@ class KernelClosureAnalysis {
|
|||
hasThisLocal = !constructor.isFactoryConstructor;
|
||||
}
|
||||
ScopeModel model = new ScopeModel();
|
||||
CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
|
||||
hasThisLocal: hasThisLocal,
|
||||
addTypeChecks: options.enableTypeAssertions);
|
||||
CapturedScopeBuilder translator =
|
||||
new CapturedScopeBuilder(model, options, hasThisLocal: hasThisLocal);
|
||||
if (entity.isField) {
|
||||
if (node is ir.Field && node.initializer != null) {
|
||||
node.accept(translator);
|
||||
|
@ -94,12 +93,8 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
/// with the stated type.
|
||||
final bool _addTypeChecks;
|
||||
|
||||
/// If true, disable the optimization of trimming out passing extra
|
||||
/// information for RTI checks.
|
||||
final bool _disableRtiOptimization;
|
||||
|
||||
KernelClosureConversionTask(Measurer measurer, this._elementMap,
|
||||
this._globalLocalsMap, this._addTypeChecks, this._disableRtiOptimization)
|
||||
this._globalLocalsMap, this._addTypeChecks)
|
||||
: super(measurer);
|
||||
|
||||
/// The combined steps of generating our intermediate representation of
|
||||
|
@ -115,19 +110,41 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
void _updateScopeBasedOnRtiNeed(
|
||||
KernelScopeInfo scope,
|
||||
ir.Node node,
|
||||
Set<ir.Node> localFunctionsNeedingRti,
|
||||
Iterable<ClassEntity> classesNeedingRti,
|
||||
bool Function(ir.Node) localFunctionNeedsSignature,
|
||||
bool Function(ClassEntity) classNeedsTypeArguments,
|
||||
bool Function(MemberEntity) methodNeedsTypeArguments,
|
||||
bool Function(ir.Node) localFunctionNeedsTypeArguments,
|
||||
MemberEntity outermostEntity) {
|
||||
if (localFunctionsNeedingRti.contains(node) ||
|
||||
classesNeedingRti.contains(outermostEntity.enclosingClass) ||
|
||||
_addTypeChecks ||
|
||||
_disableRtiOptimization) {
|
||||
if (outermostEntity is FunctionEntity &&
|
||||
outermostEntity is! ConstructorEntity) {
|
||||
scope.thisUsedAsFreeVariable = scope.thisUsedAsFreeVariableIfNeedsRti ||
|
||||
scope.thisUsedAsFreeVariable;
|
||||
} else {
|
||||
scope.freeVariables.addAll(scope.freeVariablesForRti);
|
||||
if (scope.thisUsedAsFreeVariableIfNeedsRti &&
|
||||
classNeedsTypeArguments(outermostEntity.enclosingClass)) {
|
||||
scope.thisUsedAsFreeVariable = true;
|
||||
}
|
||||
if (_addTypeChecks) {
|
||||
scope.freeVariables.addAll(scope.freeVariablesForRti);
|
||||
} else {
|
||||
for (TypeVariableTypeWithContext typeVariable
|
||||
in scope.freeVariablesForRti) {
|
||||
switch (typeVariable.kind) {
|
||||
case TypeVariableKind.cls:
|
||||
if (classNeedsTypeArguments(
|
||||
_elementMap.getClass(typeVariable.typeDeclaration))) {
|
||||
scope.freeVariables.add(typeVariable);
|
||||
}
|
||||
break;
|
||||
case TypeVariableKind.method:
|
||||
if (methodNeedsTypeArguments(
|
||||
_elementMap.getMember(typeVariable.typeDeclaration))) {
|
||||
scope.freeVariables.add(typeVariable);
|
||||
}
|
||||
break;
|
||||
case TypeVariableKind.local:
|
||||
if (localFunctionNeedsTypeArguments(typeVariable.typeDeclaration)) {
|
||||
scope.freeVariables.add(typeVariable);
|
||||
}
|
||||
break;
|
||||
case TypeVariableKind.function:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,8 +152,10 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
Iterable<FunctionEntity> createClosureEntities(
|
||||
JsClosedWorldBuilder closedWorldBuilder,
|
||||
Map<MemberEntity, ScopeModel> closureModels,
|
||||
Set<ir.Node> localFunctionsNeedingRti,
|
||||
Iterable<ClassEntity> classesNeedingRti) {
|
||||
{bool Function(ir.Node) localFunctionNeedsSignature,
|
||||
bool Function(ClassEntity) classNeedsTypeArguments,
|
||||
bool Function(FunctionEntity) methodNeedsTypeArguments,
|
||||
bool Function(ir.Node) localFunctionNeedsTypeArguments}) {
|
||||
List<FunctionEntity> callMethods = <FunctionEntity>[];
|
||||
closureModels.forEach((MemberEntity member, ScopeModel model) {
|
||||
KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
|
||||
|
@ -150,7 +169,13 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
Map<Local, JRecordField> boxedVariables =
|
||||
_elementMap.makeRecordContainer(scope, member, localsMap);
|
||||
_updateScopeBasedOnRtiNeed(
|
||||
scope, node, localFunctionsNeedingRti, classesNeedingRti, member);
|
||||
scope,
|
||||
node,
|
||||
localFunctionNeedsSignature,
|
||||
classNeedsTypeArguments,
|
||||
methodNeedsTypeArguments,
|
||||
localFunctionNeedsTypeArguments,
|
||||
member);
|
||||
|
||||
if (scope is KernelCapturedLoopScope) {
|
||||
_capturedScopesMap[node] = new JsCapturedLoopScope.from(
|
||||
|
@ -179,8 +204,10 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
functionNode,
|
||||
closuresToGenerate[node],
|
||||
allBoxedVariables,
|
||||
localFunctionsNeedingRti,
|
||||
classesNeedingRti);
|
||||
localFunctionNeedsSignature,
|
||||
classNeedsTypeArguments,
|
||||
methodNeedsTypeArguments,
|
||||
localFunctionNeedsTypeArguments);
|
||||
// Add also for the call method.
|
||||
_scopeMap[closureClassInfo.callMethod] = closureClassInfo;
|
||||
_scopeMap[closureClassInfo.signatureMethod] = closureClassInfo;
|
||||
|
@ -202,10 +229,18 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
|||
ir.FunctionNode node,
|
||||
KernelScopeInfo info,
|
||||
Map<Local, JRecordField> boxedVariables,
|
||||
Set<ir.Node> localFunctionsNeedingRti,
|
||||
Iterable<ClassEntity> classesNeedingRti) {
|
||||
bool Function(ir.Node) localFunctionNeedsSignature,
|
||||
bool Function(ClassEntity) classNeedsTypeArguments,
|
||||
bool Function(FunctionEntity) methodNeedsTypeArguments,
|
||||
bool Function(ir.Node) localFunctionNeedsTypeArguments) {
|
||||
_updateScopeBasedOnRtiNeed(
|
||||
info, node.parent, localFunctionsNeedingRti, classesNeedingRti, member);
|
||||
info,
|
||||
node.parent,
|
||||
localFunctionNeedsSignature,
|
||||
classNeedsTypeArguments,
|
||||
methodNeedsTypeArguments,
|
||||
localFunctionNeedsTypeArguments,
|
||||
member);
|
||||
KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
|
||||
KernelClosureClassInfo closureClassInfo =
|
||||
closedWorldBuilder.buildClosureClass(
|
||||
|
@ -300,8 +335,8 @@ class KernelScopeInfo {
|
|||
/// freeVariables set. Whether these variables are actually used as
|
||||
/// freeVariables will be set by the time this structure is converted to a
|
||||
/// JsScopeInfo, so JsScopeInfo does not need to use them.
|
||||
Set<TypeParameterTypeWithContext> freeVariablesForRti =
|
||||
new Set<TypeParameterTypeWithContext>();
|
||||
Set<TypeVariableTypeWithContext> freeVariablesForRti =
|
||||
new Set<TypeVariableTypeWithContext>();
|
||||
|
||||
/// If true, `this` is used as a free variable, in this scope. It is stored
|
||||
/// separately from [freeVariables] because there is no single
|
||||
|
@ -347,10 +382,10 @@ class KernelScopeInfo {
|
|||
Local _getLocal(ir.Node variable, KernelToLocalsMap localsMap,
|
||||
KernelToElementMap elementMap) {
|
||||
assert(variable is ir.VariableDeclaration ||
|
||||
variable is TypeParameterTypeWithContext);
|
||||
variable is TypeVariableTypeWithContext);
|
||||
if (variable is ir.VariableDeclaration) {
|
||||
return localsMap.getLocalVariable(variable);
|
||||
} else if (variable is TypeParameterTypeWithContext) {
|
||||
} else if (variable is TypeVariableTypeWithContext) {
|
||||
return localsMap.getLocalTypeVariable(variable.type, elementMap);
|
||||
}
|
||||
throw new ArgumentError('Only know how to get/create locals for '
|
||||
|
@ -407,7 +442,7 @@ class KernelCapturedScope extends KernelScopeInfo {
|
|||
Set<ir.VariableDeclaration> localsUsedInTryOrSync,
|
||||
Set<ir.Node /* VariableDeclaration | TypeParameterTypeWithContext */ >
|
||||
freeVariables,
|
||||
Set<TypeParameterTypeWithContext> freeVariablesForRti,
|
||||
Set<TypeVariableTypeWithContext> freeVariablesForRti,
|
||||
bool thisUsedAsFreeVariable,
|
||||
bool thisUsedAsFreeVariableIfNeedsRti,
|
||||
bool hasThisLocal)
|
||||
|
@ -449,7 +484,7 @@ class KernelCapturedLoopScope extends KernelCapturedScope {
|
|||
Set<ir.VariableDeclaration> localsUsedInTryOrSync,
|
||||
Set<ir.Node /* VariableDeclaration | TypeParameterTypeWithContext */ >
|
||||
freeVariables,
|
||||
Set<TypeParameterTypeWithContext> freeVariablesForRti,
|
||||
Set<TypeVariableTypeWithContext> freeVariablesForRti,
|
||||
bool thisUsedAsFreeVariable,
|
||||
bool thisUsedAsFreeVariableIfNeedsRti,
|
||||
bool hasThisLocal)
|
||||
|
@ -785,27 +820,78 @@ class ScopeModel {
|
|||
<ir.TreeNode, KernelScopeInfo>{};
|
||||
}
|
||||
|
||||
enum TypeVariableKind { cls, method, local, function }
|
||||
|
||||
/// A fake ir.Node that holds the TypeParameterType as well as the context in
|
||||
/// which it occurs.
|
||||
class TypeParameterTypeWithContext implements ir.Node {
|
||||
final ir.Node memberContext;
|
||||
class TypeVariableTypeWithContext implements ir.Node {
|
||||
final ir.Node context;
|
||||
final ir.TypeParameterType type;
|
||||
TypeParameterTypeWithContext(this.type, this.memberContext);
|
||||
final TypeVariableKind kind;
|
||||
final ir.TreeNode typeDeclaration;
|
||||
|
||||
factory TypeVariableTypeWithContext(
|
||||
ir.TypeParameterType type, ir.Member memberContext) {
|
||||
TypeVariableKind kind;
|
||||
ir.TreeNode context = memberContext;
|
||||
ir.TreeNode typeDeclaration = type.parameter.parent;
|
||||
if (typeDeclaration == null) {
|
||||
// We have a function type variable, like `T` in `void Function<T>(int)`.
|
||||
kind = TypeVariableKind.function;
|
||||
} else if (typeDeclaration is ir.Class) {
|
||||
// We have a class type variable, like `T` in `class Class<T> { ... }`.
|
||||
kind = TypeVariableKind.cls;
|
||||
} else if (typeDeclaration.parent is ir.Member) {
|
||||
ir.Member member = typeDeclaration.parent;
|
||||
if (member is ir.Constructor ||
|
||||
(member is ir.Procedure && member.isFactory)) {
|
||||
// We have a synthesized generic method type variable for a class type
|
||||
// variable.
|
||||
// TODO(johnniwinther): Handle constructor/factory type variables as
|
||||
// method type variables.
|
||||
kind = TypeVariableKind.cls;
|
||||
typeDeclaration = member.enclosingClass;
|
||||
} else {
|
||||
// We have a generic method type variable, like `T` in
|
||||
// `m<T>() { ... }`.
|
||||
kind = TypeVariableKind.method;
|
||||
typeDeclaration = typeDeclaration.parent;
|
||||
context = typeDeclaration;
|
||||
}
|
||||
} else {
|
||||
// We have a generic local function type variable, like `T` in
|
||||
// `m() { local<T>() { ... } ... }`.
|
||||
assert(
|
||||
typeDeclaration.parent is ir.FunctionExpression ||
|
||||
typeDeclaration.parent is ir.FunctionDeclaration,
|
||||
"Unexpected type declaration: $typeDeclaration");
|
||||
kind = TypeVariableKind.local;
|
||||
typeDeclaration = typeDeclaration.parent;
|
||||
context = typeDeclaration;
|
||||
}
|
||||
return new TypeVariableTypeWithContext.internal(
|
||||
type, context, kind, typeDeclaration);
|
||||
}
|
||||
|
||||
TypeVariableTypeWithContext.internal(
|
||||
this.type, this.context, this.kind, this.typeDeclaration);
|
||||
|
||||
accept(ir.Visitor v) {
|
||||
throw new UnsupportedError('TypeParameterTypeWithContext.accept');
|
||||
throw new UnsupportedError('TypeVariableTypeWithContext.accept');
|
||||
}
|
||||
|
||||
visitChildren(ir.Visitor v) {
|
||||
throw new UnsupportedError('TypeParameterTypeWithContext.visitChildren');
|
||||
throw new UnsupportedError('TypeVariableTypeWithContext.visitChildren');
|
||||
}
|
||||
|
||||
int get hashCode => type.hashCode;
|
||||
|
||||
bool operator ==(other) {
|
||||
if (other is! TypeParameterTypeWithContext) return false;
|
||||
return type == other.type && memberContext == other.memberContext;
|
||||
if (other is! TypeVariableTypeWithContext) return false;
|
||||
return type == other.type && context == other.context;
|
||||
}
|
||||
|
||||
String toString() => 'TypeParameterTypeWithContext $type $memberContext';
|
||||
String toString() =>
|
||||
'TypeVariableTypeWithContext(type=$type,context=$context,'
|
||||
'kind=$kind,typeDeclaration=$typeDeclaration)';
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import 'package:kernel/ast.dart' as ir;
|
||||
|
||||
import '../closure.dart';
|
||||
import '../options.dart';
|
||||
import 'closure.dart';
|
||||
|
||||
/// This builder walks the code to determine what variables are captured/free at
|
||||
|
@ -13,6 +14,8 @@ import 'closure.dart';
|
|||
class CapturedScopeBuilder extends ir.Visitor {
|
||||
ScopeModel _model;
|
||||
|
||||
CompilerOptions _options;
|
||||
|
||||
/// A map of each visited call node with the associated information about what
|
||||
/// variables are captured/used. Each ir.Node key corresponds to a scope that
|
||||
/// was encountered while visiting a closure (initially called through
|
||||
|
@ -61,17 +64,16 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
|
||||
final bool _hasThisLocal;
|
||||
|
||||
/// If true add type assetions to assert that at runtime the type is in line
|
||||
/// with the stated type.
|
||||
final bool _addTypeChecks;
|
||||
|
||||
/// Keeps track of the number of boxes that we've created so that they each
|
||||
/// have unique names.
|
||||
int _boxCounter = 0;
|
||||
|
||||
CapturedScopeBuilder(this._model, {bool hasThisLocal, bool addTypeChecks})
|
||||
: this._hasThisLocal = hasThisLocal,
|
||||
this._addTypeChecks = addTypeChecks;
|
||||
CapturedScopeBuilder(this._model, this._options, {bool hasThisLocal})
|
||||
: this._hasThisLocal = hasThisLocal;
|
||||
|
||||
/// If true add type assetions to assert that at runtime the type is in line
|
||||
/// with the stated type.
|
||||
bool get _addTypeChecks => _options.enableTypeAssertions;
|
||||
|
||||
/// Update the [CapturedScope] object corresponding to
|
||||
/// this node if any variables are captured.
|
||||
|
@ -202,7 +204,7 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
ir.Node /* VariableDeclaration | TypeParameterTypeWithContext */ variable,
|
||||
{bool onlyForRtiChecks = false}) {
|
||||
assert(variable is ir.VariableDeclaration ||
|
||||
variable is TypeParameterTypeWithContext);
|
||||
variable is TypeVariableTypeWithContext);
|
||||
if (_isInsideClosure && !_inCurrentContext(variable)) {
|
||||
// If the element is not declared in the current function and the element
|
||||
// is not the closure itself we need to mark the element as free variable.
|
||||
|
@ -230,11 +232,15 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
void visitTypeParameter(ir.TypeParameter typeParameter) {
|
||||
if (_addTypeChecks) {
|
||||
ir.TreeNode context = _executableContext;
|
||||
TypeVariableTypeWithContext typeVariable =
|
||||
new TypeVariableTypeWithContext(
|
||||
new ir.TypeParameterType(typeParameter),
|
||||
typeParameter.parent.parent);
|
||||
if (_isInsideClosure && context is ir.Procedure && context.isFactory) {
|
||||
// This is a closure in a factory constructor. Since there is no
|
||||
// [:this:], we have to mark the type arguments as free variables to
|
||||
// capture them in the closure.
|
||||
_useTypeVariableAsLocal(new ir.TypeParameterType(typeParameter));
|
||||
_useTypeVariableAsLocal(typeVariable);
|
||||
}
|
||||
|
||||
if (_executableContext is ir.Member && _executableContext is! ir.Field) {
|
||||
|
@ -247,7 +253,7 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
if (_hasThisLocal) {
|
||||
_registerNeedsThis();
|
||||
} else {
|
||||
_useTypeVariableAsLocal(new ir.TypeParameterType(typeParameter));
|
||||
_useTypeVariableAsLocal(typeVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,9 +421,9 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
/// context.
|
||||
bool _inCurrentContext(ir.Node variable) {
|
||||
assert(variable is ir.VariableDeclaration ||
|
||||
variable is TypeParameterTypeWithContext);
|
||||
if (variable is TypeParameterTypeWithContext) {
|
||||
return variable.memberContext == _executableContext;
|
||||
variable is TypeVariableTypeWithContext);
|
||||
if (variable is TypeVariableTypeWithContext) {
|
||||
return variable.context == _executableContext;
|
||||
}
|
||||
ir.TreeNode node = variable;
|
||||
while (node != _outermostNode && node != _executableContext) {
|
||||
|
@ -453,16 +459,13 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
|
||||
@override
|
||||
visitTypeParameterType(ir.TypeParameterType type) {
|
||||
if (_outermostNode is ir.Member) {
|
||||
ir.Member outermostMember = _outermostNode;
|
||||
if (_isFieldOrConstructor(_outermostNode)) {
|
||||
_useTypeVariableAsLocal(type, onlyForRtiChecks: true);
|
||||
} else if (type.parameter.parent is ir.FunctionNode) {
|
||||
// This is a function type parameter reference: foo<T>(...) {...}
|
||||
_useTypeVariableAsLocal(type, onlyForRtiChecks: true);
|
||||
} else if (outermostMember.isInstanceMember) {
|
||||
_registerNeedsThis(onlyIfNeedsRti: true);
|
||||
}
|
||||
_analyzeTypeVariable(type);
|
||||
}
|
||||
|
||||
@override
|
||||
visitTypeLiteral(ir.TypeLiteral node) {
|
||||
if (node.type is ir.TypeParameterType) {
|
||||
_analyzeTypeVariable(node.type, onlyIfNeedsRti: false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,11 +476,44 @@ class CapturedScopeBuilder extends ir.Visitor {
|
|||
node is ir.Field ||
|
||||
(node is ir.Procedure && node.isFactory);
|
||||
|
||||
void _analyzeTypeVariable(ir.TypeParameterType type,
|
||||
{bool onlyIfNeedsRti: true}) {
|
||||
if (_outermostNode is ir.Member) {
|
||||
TypeVariableTypeWithContext typeVariable =
|
||||
new TypeVariableTypeWithContext(type, _outermostNode);
|
||||
switch (typeVariable.kind) {
|
||||
case TypeVariableKind.cls:
|
||||
if (_isFieldOrConstructor(_outermostNode)) {
|
||||
// Class type variable used in a field or constructor.
|
||||
_useTypeVariableAsLocal(typeVariable,
|
||||
onlyForRtiChecks: onlyIfNeedsRti);
|
||||
} else {
|
||||
// Class type variable used in a method.
|
||||
_registerNeedsThis(onlyIfNeedsRti: onlyIfNeedsRti);
|
||||
}
|
||||
break;
|
||||
case TypeVariableKind.method:
|
||||
case TypeVariableKind.local:
|
||||
_useTypeVariableAsLocal(typeVariable,
|
||||
onlyForRtiChecks: onlyIfNeedsRti);
|
||||
break;
|
||||
case TypeVariableKind.function:
|
||||
// The type variable is a function type variable, like `T` in
|
||||
//
|
||||
// List<void Function<T>(T)> list;
|
||||
//
|
||||
// which doesn't correspond to a captured local variable.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If [onlyForRtiChecks] is true, the variable will be added to a list
|
||||
/// indicating it *may* be used only if runtime type information is checked.
|
||||
void _useTypeVariableAsLocal(ir.TypeParameterType type,
|
||||
{bool onlyForRtiChecks = false}) {
|
||||
_markVariableAsUsed(new TypeParameterTypeWithContext(type, _outermostNode),
|
||||
onlyForRtiChecks: onlyForRtiChecks);
|
||||
void _useTypeVariableAsLocal(TypeVariableTypeWithContext typeVariable,
|
||||
{bool onlyForRtiChecks: false}) {
|
||||
if (typeVariable.kind != TypeVariableKind.cls && !_options.strongMode) {
|
||||
return;
|
||||
}
|
||||
_markVariableAsUsed(typeVariable, onlyForRtiChecks: onlyForRtiChecks);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import '../elements/entities.dart';
|
|||
import '../elements/names.dart';
|
||||
import '../elements/types.dart';
|
||||
import '../kernel/indexed.dart';
|
||||
import 'closure.dart' show KernelClosureClassInfo;
|
||||
|
||||
/// Map from 'frontend' to 'backend' elements.
|
||||
///
|
||||
|
@ -522,17 +521,11 @@ class JField extends JMember implements FieldEntity, IndexedField {
|
|||
}
|
||||
|
||||
class JClosureCallMethod extends JMethod {
|
||||
JClosureCallMethod(KernelClosureClassInfo closureClassInfo,
|
||||
JClosureCallMethod(ClassEntity enclosingClass,
|
||||
ParameterStructure parameterStructure, AsyncMarker asyncMarker)
|
||||
: super(
|
||||
closureClassInfo.closureClassEntity.library,
|
||||
closureClassInfo.closureClassEntity,
|
||||
Names.call,
|
||||
parameterStructure,
|
||||
asyncMarker,
|
||||
isStatic: false,
|
||||
isExternal: false,
|
||||
isAbstract: false);
|
||||
: super(enclosingClass.library, enclosingClass, Names.call,
|
||||
parameterStructure, asyncMarker,
|
||||
isStatic: false, isExternal: false, isAbstract: false);
|
||||
|
||||
String get _kind => 'closure_call';
|
||||
}
|
||||
|
|
|
@ -73,12 +73,8 @@ class JsBackendStrategy implements KernelBackendStrategy {
|
|||
_compiler.reporter, _compiler.environment, strategy.elementMap);
|
||||
_elementEnvironment = _elementMap.elementEnvironment;
|
||||
_commonElements = _elementMap.commonElements;
|
||||
_closureDataLookup = new KernelClosureConversionTask(
|
||||
_compiler.measurer,
|
||||
_elementMap,
|
||||
_globalLocalsMap,
|
||||
_compiler.options.enableTypeAssertions,
|
||||
_compiler.options.disableRtiOptimization);
|
||||
_closureDataLookup = new KernelClosureConversionTask(_compiler.measurer,
|
||||
_elementMap, _globalLocalsMap, _compiler.options.enableTypeAssertions);
|
||||
JsClosedWorldBuilder closedWorldBuilder = new JsClosedWorldBuilder(
|
||||
_elementMap, _closureDataLookup, _compiler.options);
|
||||
return closedWorldBuilder._convertClosedWorld(
|
||||
|
@ -278,10 +274,11 @@ class JsClosedWorldBuilder {
|
|||
if (_options.disableRtiOptimization) {
|
||||
rtiNeed = new TrivialRuntimeTypesNeed();
|
||||
callMethods = _closureConversionTask.createClosureEntities(
|
||||
this,
|
||||
map.toBackendMemberMap(closureModels, identity),
|
||||
new Set<ir.Node>(),
|
||||
_classSets.keys.toList());
|
||||
this, map.toBackendMemberMap(closureModels, identity),
|
||||
localFunctionNeedsSignature: (_) => true,
|
||||
classNeedsTypeArguments: (_) => true,
|
||||
methodNeedsTypeArguments: (_) => true,
|
||||
localFunctionNeedsTypeArguments: (_) => true);
|
||||
} else {
|
||||
RuntimeTypesNeedImpl kernelRtiNeed = closedWorld.rtiNeed;
|
||||
Set<ir.Node> localFunctionsNodesNeedingSignature = new Set<ir.Node>();
|
||||
|
@ -298,11 +295,17 @@ class JsClosedWorldBuilder {
|
|||
Set<ClassEntity> classesNeedingTypeArguments =
|
||||
map.toBackendClassSet(kernelRtiNeed.classesNeedingTypeArguments);
|
||||
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments =
|
||||
map.toBackendFunctionSet(kernelRtiNeed.methodsNeedingTypeArguments);
|
||||
|
||||
callMethods = _closureConversionTask.createClosureEntities(
|
||||
this,
|
||||
map.toBackendMemberMap(closureModels, identity),
|
||||
localFunctionsNodesNeedingSignature,
|
||||
classesNeedingTypeArguments);
|
||||
this, map.toBackendMemberMap(closureModels, identity),
|
||||
localFunctionNeedsSignature:
|
||||
localFunctionsNodesNeedingSignature.contains,
|
||||
classNeedsTypeArguments: classesNeedingTypeArguments.contains,
|
||||
methodNeedsTypeArguments: methodsNeedingTypeArguments.contains,
|
||||
localFunctionNeedsTypeArguments:
|
||||
localFunctionsNodesNeedingTypeArguments.contains);
|
||||
|
||||
List<FunctionEntity> callMethodsNeedingSignature = <FunctionEntity>[];
|
||||
for (ir.Node node in localFunctionsNodesNeedingSignature) {
|
||||
|
@ -321,7 +324,8 @@ class JsClosedWorldBuilder {
|
|||
kernelRtiNeed,
|
||||
callMethodsNeedingSignature,
|
||||
callMethodsNeedingTypeArguments,
|
||||
classesNeedingTypeArguments);
|
||||
classesNeedingTypeArguments,
|
||||
methodsNeedingTypeArguments);
|
||||
}
|
||||
|
||||
NoSuchMethodDataImpl oldNoSuchMethodData = closedWorld.noSuchMethodData;
|
||||
|
@ -497,15 +501,14 @@ class JsClosedWorldBuilder {
|
|||
RuntimeTypesNeedImpl rtiNeed,
|
||||
List<FunctionEntity> callMethodsNeedingSignature,
|
||||
List<FunctionEntity> callMethodsNeedingTypeArguments,
|
||||
Set<ClassEntity> classesNeedingTypeArguments) {
|
||||
Set<ClassEntity> classesNeedingTypeArguments,
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments) {
|
||||
Set<FunctionEntity> methodsNeedingSignature =
|
||||
map.toBackendFunctionSet(rtiNeed.methodsNeedingSignature);
|
||||
methodsNeedingSignature.addAll(callMethodsNeedingSignature);
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments =
|
||||
map.toBackendFunctionSet(rtiNeed.methodsNeedingTypeArguments);
|
||||
methodsNeedingTypeArguments.addAll(callMethodsNeedingTypeArguments);
|
||||
Set<ClassEntity> classesUsingTypeVariableExpression =
|
||||
map.toBackendClassSet(rtiNeed.classesUsingTypeVariableExpression);
|
||||
map.toBackendClassSet(rtiNeed.classesUsingTypeVariableLiterals);
|
||||
return new RuntimeTypesNeedImpl(
|
||||
_elementEnvironment,
|
||||
backendUsage,
|
||||
|
|
|
@ -2439,6 +2439,22 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
closureEntity = new JLocal('', localsMap.currentMember);
|
||||
}
|
||||
|
||||
FunctionEntity callMethod = new JClosureCallMethod(
|
||||
classEntity, _getParameterStructure(node), getAsyncMarker(node));
|
||||
_nestedClosureMap
|
||||
.putIfAbsent(member, () => <FunctionEntity>[])
|
||||
.add(callMethod);
|
||||
// We need create the type variable here - before we try to make local
|
||||
// variables from them (in `JsScopeInfo.from` called through
|
||||
// `KernelClosureClassInfo.fromScopeInfo` below).
|
||||
int index = 0;
|
||||
for (ir.TypeParameter typeParameter in node.typeParameters) {
|
||||
_typeVariableMap[typeParameter] = _typeVariables.register(
|
||||
createTypeVariable(callMethod, typeParameter.name, index),
|
||||
new TypeVariableData(typeParameter));
|
||||
index++;
|
||||
}
|
||||
|
||||
KernelClosureClassInfo closureClassInfo =
|
||||
new KernelClosureClassInfo.fromScopeInfo(
|
||||
classEntity,
|
||||
|
@ -2457,18 +2473,6 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
memberThisType, location, typeVariableAccess);
|
||||
}
|
||||
|
||||
FunctionEntity callMethod = new JClosureCallMethod(
|
||||
closureClassInfo, _getParameterStructure(node), getAsyncMarker(node));
|
||||
_nestedClosureMap
|
||||
.putIfAbsent(member, () => <FunctionEntity>[])
|
||||
.add(callMethod);
|
||||
int index = 0;
|
||||
for (ir.TypeParameter typeParameter in node.typeParameters) {
|
||||
_typeVariableMap[typeParameter] = _typeVariables.register(
|
||||
createTypeVariable(callMethod, typeParameter.name, index),
|
||||
new TypeVariableData(typeParameter));
|
||||
index++;
|
||||
}
|
||||
_members.register<IndexedFunction, FunctionData>(
|
||||
callMethod,
|
||||
new ClosureFunctionData(
|
||||
|
@ -2548,7 +2552,7 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
fieldNumber);
|
||||
fieldNumber++;
|
||||
}
|
||||
} else if (variable is TypeParameterTypeWithContext) {
|
||||
} else if (variable is TypeVariableTypeWithContext) {
|
||||
_constructClosureField(
|
||||
localsMap.getLocalTypeVariable(variable.type, this),
|
||||
closureClassInfo,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'dart:io' hide Link;
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:compiler/src/closure.dart';
|
||||
import 'package:compiler/src/commandline_options.dart';
|
||||
import 'package:compiler/src/common.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
|
||||
|
@ -28,13 +27,7 @@ main(List<String> args) {
|
|||
asyncTest(() async {
|
||||
Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
|
||||
await checkTests(dataDir, computeClosureData, computeKernelClosureData,
|
||||
skipForKernel: skipForKernel,
|
||||
options: [
|
||||
Flags.disableTypeInference,
|
||||
// TODO(redemption): Enable inlining.
|
||||
Flags.disableInlining
|
||||
],
|
||||
args: args);
|
||||
skipForKernel: skipForKernel, args: args);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
140
tests/compiler/dart2js/closure/data/generic_strong.dart
Normal file
140
tests/compiler/dart2js/closure/data/generic_strong.dart
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) 2018, 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.
|
||||
|
||||
class Class1<T> {
|
||||
/*element: Class1.field:hasThis*/
|
||||
var field = /*fields=[T],free=[T],hasThis*/ () => T;
|
||||
|
||||
/*element: Class1.funcField:hasThis*/
|
||||
Function funcField;
|
||||
|
||||
/*element: Class1.:hasThis*/
|
||||
Class1() {
|
||||
field = /*fields=[T],free=[T],hasThis*/ () => T;
|
||||
}
|
||||
|
||||
/*element: Class1.setFunc:hasThis*/
|
||||
Class1.setFunc(this.funcField);
|
||||
|
||||
/*element: Class1.fact:*/
|
||||
factory Class1.fact() => new Class1<T>();
|
||||
|
||||
/*element: Class1.fact2:*/
|
||||
factory Class1.fact2() =>
|
||||
new Class1.setFunc(/*fields=[T],free=[T]*/ () => new Set<T>());
|
||||
|
||||
/*element: Class1.method1:hasThis*/
|
||||
method1() => T;
|
||||
|
||||
/*element: Class1.method2:hasThis*/
|
||||
method2() {
|
||||
return /*fields=[this],free=[this],hasThis*/ () => T;
|
||||
}
|
||||
|
||||
/*element: Class1.method3:hasThis*/
|
||||
method3<S>() => S;
|
||||
|
||||
/*element: Class1.method4:hasThis*/
|
||||
method4<S>() {
|
||||
return /*fields=[S],free=[S],hasThis*/ () => S;
|
||||
}
|
||||
|
||||
/*element: Class1.method5:hasThis*/
|
||||
method5() {
|
||||
/*hasThis*/ local<S>() {
|
||||
return /*fields=[S],free=[S],hasThis*/ () => S;
|
||||
}
|
||||
|
||||
return local<double>();
|
||||
}
|
||||
|
||||
/*element: Class1.method6:hasThis*/
|
||||
method6<S>() {
|
||||
/*fields=[S],free=[S],hasThis*/ local<U>() {
|
||||
return /*fields=[S,U],free=[S,U],hasThis*/ () => '$S$U';
|
||||
}
|
||||
|
||||
var local2 = /*fields=[S,this],free=[S,this],hasThis*/ (o) {
|
||||
return /*fields=[S,this],free=[S,this],hasThis*/ () => new Map<T, S>();
|
||||
};
|
||||
return local2(local<double>());
|
||||
}
|
||||
|
||||
/*element: Class1.staticMethod1:*/
|
||||
static staticMethod1<S>() => S;
|
||||
|
||||
/*element: Class1.staticMethod2:*/
|
||||
static staticMethod2<S>() {
|
||||
return /*fields=[S],free=[S]*/ () => S;
|
||||
}
|
||||
|
||||
/*element: Class1.staticMethod3:*/
|
||||
static staticMethod3() {
|
||||
local<S>() {
|
||||
return /*fields=[S],free=[S]*/ () => S;
|
||||
}
|
||||
|
||||
return local<double>();
|
||||
}
|
||||
|
||||
/*element: Class1.staticMethod4:*/
|
||||
static staticMethod4<S>() {
|
||||
/*fields=[S],free=[S]*/ local<U>() {
|
||||
return /*fields=[S,U],free=[S,U]*/ () => '$S$U';
|
||||
}
|
||||
|
||||
var local2 = /*fields=[S],free=[S]*/ (o) {
|
||||
return /*fields=[S],free=[S]*/ () => new Set<S>();
|
||||
};
|
||||
return local2(local<double>());
|
||||
}
|
||||
}
|
||||
|
||||
/*element: topLevelMethod1:*/
|
||||
topLevelMethod1<S>() => S;
|
||||
|
||||
/*element: topLevelMethod2:*/
|
||||
topLevelMethod2<S>() {
|
||||
return /*fields=[S],free=[S]*/ () => S;
|
||||
}
|
||||
|
||||
/*element: topLevelMethod3:*/
|
||||
topLevelMethod3() {
|
||||
local<S>() {
|
||||
return /*fields=[S],free=[S]*/ () => S;
|
||||
}
|
||||
|
||||
return local<double>();
|
||||
}
|
||||
|
||||
/*element: topLevelMethod4:*/
|
||||
topLevelMethod4<S>() {
|
||||
/*fields=[S],free=[S]*/ local<U>() {
|
||||
return /*fields=[S,U],free=[S,U]*/ () => '$S$U';
|
||||
}
|
||||
|
||||
var local2 = /*fields=[S],free=[S]*/ (o) {
|
||||
return /*fields=[S],free=[S]*/ () => new Set<S>();
|
||||
};
|
||||
return local2(local<double>());
|
||||
}
|
||||
|
||||
/*element: main:*/
|
||||
main() {
|
||||
new Class1<int>().method1();
|
||||
new Class1<int>.fact().method2();
|
||||
new Class1<int>.fact2().funcField() is Set;
|
||||
new Class1<int>().method3<double>();
|
||||
new Class1<int>().method4<double>();
|
||||
new Class1<int>().method5();
|
||||
new Class1<int>().method6<double>();
|
||||
Class1.staticMethod1<double>();
|
||||
Class1.staticMethod2<double>();
|
||||
Class1.staticMethod3();
|
||||
Class1.staticMethod4<double>();
|
||||
topLevelMethod1<double>();
|
||||
topLevelMethod2<double>();
|
||||
topLevelMethod3();
|
||||
topLevelMethod4<double>();
|
||||
}
|
|
@ -386,7 +386,10 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
|
|||
List<String> testOptions = options.toList();
|
||||
if (name.endsWith('_ea.dart')) {
|
||||
testOptions.add(Flags.enableAsserts);
|
||||
} else if (name.endsWith('_strong.dart')) {
|
||||
testOptions.add(Flags.strongMode);
|
||||
}
|
||||
|
||||
print('----------------------------------------------------------------');
|
||||
print('Test: $name');
|
||||
// Pretend this is a dart2js_native test to allow use of 'native' keyword
|
||||
|
@ -431,7 +434,7 @@ Future checkTests(Directory dataDir, ComputeMemberDataFunction computeFromAst,
|
|||
|
||||
if (setUpFunction != null) setUpFunction();
|
||||
|
||||
if (skipForAst.contains(name)) {
|
||||
if (skipForAst.contains(name) || testOptions.contains(Flags.strongMode)) {
|
||||
print('--skipped for ast-----------------------------------------------');
|
||||
} else {
|
||||
print('--from ast------------------------------------------------------');
|
||||
|
|
|
@ -72,8 +72,12 @@ CompilerDiagnostics createCompilerDiagnostics(
|
|||
Expando<MemorySourceFileProvider> expando =
|
||||
new Expando<MemorySourceFileProvider>();
|
||||
|
||||
// Cached kernel state for non-strong mode.
|
||||
fe.InitializedCompilerState kernelInitializedCompilerState;
|
||||
|
||||
// Cached kernel state for strong mode.
|
||||
fe.InitializedCompilerState strongKernelInitializedCompilerState;
|
||||
|
||||
/// memorySourceFiles can contain a map of string filename to string file
|
||||
/// contents or string file name to binary file contents (hence the `dynamic`
|
||||
/// type for the second parameter).
|
||||
|
@ -110,14 +114,20 @@ Future<CompilationResult> runCompiler(
|
|||
if (beforeRun != null) {
|
||||
beforeRun(compiler);
|
||||
}
|
||||
fe.InitializedCompilerState compilerState;
|
||||
bool isSuccess = await compiler.run(entryPoint);
|
||||
if (compiler.libraryLoader is KernelLibraryLoaderTask) {
|
||||
KernelLibraryLoaderTask loader = compiler.libraryLoader;
|
||||
kernelInitializedCompilerState = loader.initializedCompilerState;
|
||||
if (compiler.options.strongMode) {
|
||||
compilerState = strongKernelInitializedCompilerState =
|
||||
loader.initializedCompilerState;
|
||||
} else {
|
||||
compilerState =
|
||||
kernelInitializedCompilerState = loader.initializedCompilerState;
|
||||
}
|
||||
}
|
||||
return new CompilationResult(compiler,
|
||||
isSuccess: isSuccess,
|
||||
kernelInitializedCompilerState: kernelInitializedCompilerState);
|
||||
isSuccess: isSuccess, kernelInitializedCompilerState: compilerState);
|
||||
}
|
||||
|
||||
CompilerImpl compilerFor(
|
||||
|
@ -172,21 +182,25 @@ CompilerImpl compilerFor(
|
|||
outputProvider = const NullCompilerOutput();
|
||||
}
|
||||
|
||||
CompilerOptions compilerOptions = new CompilerOptions.parse(
|
||||
entryPoint: entryPoint,
|
||||
resolutionInputs: resolutionInputs,
|
||||
libraryRoot: libraryRoot,
|
||||
packageRoot: packageRoot,
|
||||
options: options,
|
||||
environment: {},
|
||||
platformBinaries: platformBinaries,
|
||||
packageConfig: packageConfig,
|
||||
packagesDiscoveryProvider: packagesDiscoveryProvider);
|
||||
if (compilerOptions.strongMode) {
|
||||
compilerOptions.kernelInitializedCompilerState =
|
||||
strongKernelInitializedCompilerState;
|
||||
} else {
|
||||
compilerOptions.kernelInitializedCompilerState =
|
||||
kernelInitializedCompilerState;
|
||||
}
|
||||
CompilerImpl compiler = new CompilerImpl(
|
||||
provider,
|
||||
outputProvider,
|
||||
diagnosticHandler,
|
||||
new CompilerOptions.parse(
|
||||
entryPoint: entryPoint,
|
||||
resolutionInputs: resolutionInputs,
|
||||
libraryRoot: libraryRoot,
|
||||
packageRoot: packageRoot,
|
||||
options: options,
|
||||
environment: {},
|
||||
platformBinaries: platformBinaries,
|
||||
packageConfig: packageConfig,
|
||||
packagesDiscoveryProvider: packagesDiscoveryProvider)
|
||||
..kernelInitializedCompilerState = kernelInitializedCompilerState);
|
||||
provider, outputProvider, diagnosticHandler, compilerOptions);
|
||||
|
||||
if (cachedCompiler != null) {
|
||||
Map copiedLibraries = {};
|
||||
|
|
|
@ -4,9 +4,66 @@
|
|||
|
||||
/*class: A:needsArgs,exp*/
|
||||
class A<T> {
|
||||
m() => T;
|
||||
instanceMethod() => T;
|
||||
|
||||
/*ast.element: A.staticMethod:exp*/
|
||||
/*kernel.element: A.staticMethod:needsArgs,exp*/
|
||||
static staticMethod<S>() => S;
|
||||
|
||||
/*ast.element: A.staticMethodNested:exp*/
|
||||
/*kernel.element: A.staticMethodNested:needsArgs,exp*/
|
||||
static staticMethodNested<S>() {
|
||||
var inner = () => S;
|
||||
return inner();
|
||||
}
|
||||
|
||||
/*ast.element: A.genericMethod:exp*/
|
||||
/*kernel.element: A.genericMethod:needsArgs,exp*/
|
||||
genericMethod<S>() => S;
|
||||
|
||||
/*ast.element: A.genericMethodNested:exp*/
|
||||
/*kernel.element: A.genericMethodNested:needsArgs,exp*/
|
||||
genericMethodNested<S>() {
|
||||
var inner = () => S;
|
||||
return inner();
|
||||
}
|
||||
|
||||
localFunction() {
|
||||
/*ast.exp*/ /*kernel.needsArgs,exp*/ local<S>() => S;
|
||||
|
||||
return local<bool>();
|
||||
}
|
||||
|
||||
localFunctionNested() {
|
||||
/*ast.exp*/ /*kernel.needsArgs,exp*/ local<S>() {
|
||||
var inner = () => S;
|
||||
return inner();
|
||||
}
|
||||
|
||||
return local<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
/*ast.element: topLevelMethod:exp*/
|
||||
/*kernel.element: topLevelMethod:needsArgs,exp*/
|
||||
topLevelMethod<S>() => S;
|
||||
|
||||
/*ast.element: topLevelMethodNested:exp*/
|
||||
/*kernel.element: topLevelMethodNested:needsArgs,exp*/
|
||||
topLevelMethodNested<S>() {
|
||||
var inner = () => S;
|
||||
return inner();
|
||||
}
|
||||
|
||||
main() {
|
||||
new A<int>().m();
|
||||
var a = new A<int>();
|
||||
a.instanceMethod();
|
||||
a.genericMethod<String>();
|
||||
a.genericMethodNested<String>();
|
||||
a.localFunction();
|
||||
a.localFunctionNested();
|
||||
A.staticMethod<double>();
|
||||
A.staticMethodNested<double>();
|
||||
topLevelMethod<num>();
|
||||
topLevelMethodNested<num>();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:compiler/src/tree/nodes.dart' as ast;
|
|||
import 'package:compiler/src/js_backend/runtime_types.dart';
|
||||
import 'package:compiler/src/kernel/element_map.dart';
|
||||
import 'package:compiler/src/kernel/kernel_backend_strategy.dart';
|
||||
import 'package:compiler/src/kernel/kernel_strategy.dart';
|
||||
import 'package:compiler/src/ssa/builder.dart' as ast;
|
||||
import 'package:compiler/src/universe/world_builder.dart';
|
||||
import 'package:kernel/ast.dart' as ir;
|
||||
|
@ -114,7 +115,7 @@ abstract class ComputeValueMixin<T> {
|
|||
}
|
||||
ClassEntity frontendClass = getFrontendClass(backendClass);
|
||||
comma = findDependencies(sb, comma, frontendClass);
|
||||
if (rtiNeedBuilder.classesUsingTypeVariableExpression
|
||||
if (rtiNeedBuilder.classesUsingTypeVariableLiterals
|
||||
.contains(frontendClass)) {
|
||||
sb.write('${comma}exp');
|
||||
comma = ',';
|
||||
|
@ -146,16 +147,30 @@ abstract class ComputeValueMixin<T> {
|
|||
sb.write('${comma}needsSignature');
|
||||
comma = ',';
|
||||
}
|
||||
if (frontendClosure != null &&
|
||||
rtiNeed.localFunctionNeedsSignature(frontendClosure)) {
|
||||
sb.write('${comma}needsSignature');
|
||||
comma = ',';
|
||||
if (frontendClosure != null) {
|
||||
if (frontendClosure is LocalFunctionElement &&
|
||||
rtiNeed.localFunctionNeedsSignature(frontendClosure)) {
|
||||
sb.write('${comma}needsSignature');
|
||||
comma = ',';
|
||||
}
|
||||
if (rtiNeedBuilder.localFunctionsUsingTypeVariableLiterals
|
||||
.contains(frontendClosure)) {
|
||||
sb.write('${comma}exp');
|
||||
comma = ',';
|
||||
}
|
||||
}
|
||||
if (frontendMember != null) {
|
||||
if (rtiNeedBuilder.methodsUsingTypeVariableLiterals
|
||||
.contains(frontendMember)) {
|
||||
sb.write('${comma}exp');
|
||||
comma = ',';
|
||||
}
|
||||
comma = findDependencies(sb, comma, frontendMember);
|
||||
comma = findChecks(
|
||||
sb, comma, 'explicit', frontendMember, rtiNeedBuilder.isChecks);
|
||||
comma = findChecks(sb, comma, 'implicit', frontendMember,
|
||||
rtiNeedBuilder.implicitIsChecks);
|
||||
}
|
||||
comma = findDependencies(sb, comma, frontendMember);
|
||||
comma = findChecks(
|
||||
sb, comma, 'explicit', frontendMember, rtiNeedBuilder.isChecks);
|
||||
comma = findChecks(sb, comma, 'implicit', frontendMember,
|
||||
rtiNeedBuilder.implicitIsChecks);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -332,7 +347,17 @@ abstract class IrMixin implements ComputeValueMixin<ir.Node> {
|
|||
}
|
||||
|
||||
@override
|
||||
Local getFrontendClosure(MemberEntity member) => null;
|
||||
Local getFrontendClosure(MemberEntity member) {
|
||||
KernelBackendStrategy backendStrategy = compiler.backendStrategy;
|
||||
ir.Node node = backendStrategy.elementMap.getMemberDefinition(member).node;
|
||||
if (node is ir.FunctionDeclaration || node is ir.FunctionExpression) {
|
||||
KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
|
||||
KernelToElementMapForImpact frontendElementMap =
|
||||
frontendStrategy.elementMap;
|
||||
return frontendElementMap.getLocalFunction(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class RtiClassNeedIrComputer extends DataRegistry
|
||||
|
|
Loading…
Reference in a new issue