Add @pragma('dart2js:disableFinal')
Change-Id: I9b3f878803f946d08979144028d08b1a4dc4612f
Reviewed-on: https://dart-review.googlesource.com/c/86924
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Auto-Submit: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/frontend_strategy.dart b/pkg/compiler/lib/src/frontend_strategy.dart
index 1508076..23a1cee 100644
--- a/pkg/compiler/lib/src/frontend_strategy.dart
+++ b/pkg/compiler/lib/src/frontend_strategy.dart
@@ -12,6 +12,7 @@
import 'elements/entities.dart';
import 'elements/types.dart';
import 'enqueue.dart';
+import 'js_backend/annotations.dart';
import 'js_backend/allocator_analysis.dart' show KAllocatorAnalysis;
import 'js_backend/backend_usage.dart';
import 'js_backend/interceptor_data.dart';
@@ -72,6 +73,7 @@
KAllocatorAnalysis allocatorAnalysis,
NativeResolutionEnqueuer nativeResolutionEnqueuer,
NoSuchMethodRegistry noSuchMethodRegistry,
+ AnnotationsDataBuilder annotationsDataBuilder,
SelectorConstraintsStrategy selectorConstraintsStrategy,
ClassHierarchyBuilder classHierarchyBuilder,
ClassQueries classQueries);
@@ -81,6 +83,7 @@
WorkItemBuilder createResolutionWorkItemBuilder(
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
+ AnnotationsDataBuilder annotationsDataBuilder,
ImpactTransformer impactTransformer,
Map<Entity, WorldImpact> impactCache);
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index 3206a45..4003b5b 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -40,8 +40,14 @@
Map<ir.Expression, ir.DartType> get cachedStaticTypes => _cache;
+ /// If `true`, the effect of executing assert statements is taken into account
+ /// when computing the static type.
bool get useAsserts;
+ /// If `true`, the static type of an effectively final variable is inferred
+ /// from the static type of its initializer.
+ bool get inferEffectivelyFinalVariableTypes;
+
VariableScopeModel get variableScopeModel;
bool completes(ir.DartType type) => type != const ir.BottomType();
@@ -1155,7 +1161,8 @@
_currentVariables.add(node);
ir.DartType type = visitNode(node.initializer);
if (node.initializer != null &&
- variableScopeModel.isEffectivelyFinal(node)) {
+ variableScopeModel.isEffectivelyFinal(node) &&
+ inferEffectivelyFinalVariableTypes) {
node.type = type;
}
handleVariableDeclaration(node);
diff --git a/pkg/compiler/lib/src/js_backend/annotations.dart b/pkg/compiler/lib/src/js_backend/annotations.dart
index bd195e7..96ed552 100644
--- a/pkg/compiler/lib/src/js_backend/annotations.dart
+++ b/pkg/compiler/lib/src/js_backend/annotations.dart
@@ -42,141 +42,159 @@
return false;
}
-/// Process backend specific annotations.
-// TODO(johnniwinther): Merge this with [AnnotationProcessor].
-AnnotationsData processAnnotations(
+enum PragmaAnnotation {
+ noInline,
+ tryInline,
+ disableFinal,
+ noThrows,
+ noSideEffects,
+ trustTypeAnnotations,
+ assumeDynamic,
+}
+
+Set<PragmaAnnotation> processMemberAnnotations(
DiagnosticReporter reporter,
KCommonElements commonElements,
KElementEnvironment elementEnvironment,
- Iterable<MemberEntity> processedMembers) {
- AnnotationsDataBuilder annotationsDataBuilder = new AnnotationsDataBuilder();
+ AnnotationsDataBuilder annotationsDataBuilder,
+ MemberEntity element) {
+ Set<PragmaAnnotation> values = new Set<PragmaAnnotation>();
+ bool hasNoInline = false;
+ bool hasTryInline = false;
+ bool disableFinal = false;
- void processMemberAnnotations(MemberEntity element) {
- bool hasNoInline = false;
- bool hasTryInline = false;
+ if (_trustTypeAnnotations(elementEnvironment, commonElements, element)) {
+ values.add(PragmaAnnotation.trustTypeAnnotations);
+ annotationsDataBuilder.registerTrustTypeAnnotations(element);
+ }
- if (_trustTypeAnnotations(elementEnvironment, commonElements, element)) {
- annotationsDataBuilder.registerTrustTypeAnnotations(element);
- }
+ if (_assumeDynamic(elementEnvironment, commonElements, element)) {
+ values.add(PragmaAnnotation.assumeDynamic);
+ annotationsDataBuilder.registerAssumeDynamic(element);
+ }
- if (_assumeDynamic(elementEnvironment, commonElements, element)) {
- annotationsDataBuilder.registerAssumeDynamic(element);
- }
+ // TODO(sra): Check for inappropriate annotations on fields.
+ if (element.isField) {
+ return values;
+ }
- // TODO(sra): Check for inappropriate annotations on fields.
- if (element.isField) return;
+ FunctionEntity method = element;
+ LibraryEntity library = element.library;
+ bool platformAnnotationsAllowed = library.canonicalUri.scheme == 'dart' ||
+ maybeEnableNative(library.canonicalUri);
- FunctionEntity method = element;
- LibraryEntity library = element.library;
- bool platformAnnotationsAllowed = library.canonicalUri.scheme == 'dart' ||
- maybeEnableNative(library.canonicalUri);
+ bool hasNoThrows = false;
+ bool hasNoSideEffects = false;
- bool hasNoThrows = false;
- bool hasNoSideEffects = false;
+ for (ConstantValue constantValue
+ in elementEnvironment.getMemberMetadata(method)) {
+ if (!constantValue.isConstructedObject) continue;
+ ConstructedConstantValue value = constantValue;
+ ClassEntity cls = value.type.element;
+ assert(cls != null); // Unresolved classes null.
- for (ConstantValue constantValue
- in elementEnvironment.getMemberMetadata(method)) {
- if (!constantValue.isConstructedObject) continue;
- ConstructedConstantValue value = constantValue;
- ClassEntity cls = value.type.element;
- assert(cls != null); // Unresolved classes null.
-
- if (platformAnnotationsAllowed) {
- if (cls == commonElements.forceInlineClass) {
- hasTryInline = true;
- } else if (cls == commonElements.noInlineClass) {
- hasNoInline = true;
- } else if (cls == commonElements.noThrowsClass) {
- hasNoThrows = true;
- bool isValid = true;
- if (method.isTopLevel) {
- isValid = true;
- } else if (method.isStatic) {
- isValid = true;
- } else if (method is ConstructorEntity &&
- method.isFactoryConstructor) {
- isValid = true;
- }
- if (!isValid) {
- reporter.internalError(
- method,
- "@NoThrows() is currently limited to top-level"
- " or static functions and factory constructors.");
- }
- annotationsDataBuilder.registerCannotThrow(method);
- } else if (cls == commonElements.noSideEffectsClass) {
- hasNoSideEffects = true;
- annotationsDataBuilder.registerSideEffectsFree(method);
- }
- }
-
- if (cls == commonElements.expectNoInlineClass) {
- hasNoInline = true;
- } else if (cls == commonElements.metaNoInlineClass) {
- hasNoInline = true;
- } else if (cls == commonElements.metaTryInlineClass) {
+ if (platformAnnotationsAllowed) {
+ if (cls == commonElements.forceInlineClass) {
hasTryInline = true;
- } else if (cls == commonElements.pragmaClass) {
- // Recognize:
- //
- // @pragma('dart2js:noInline')
- // @pragma('dart2js:tryInline')
- //
- ConstantValue nameValue =
- value.fields[commonElements.pragmaClassNameField];
- if (nameValue == null || !nameValue.isString) continue;
- String name = (nameValue as StringConstantValue).stringValue;
- if (!name.startsWith('dart2js:')) continue;
-
- ConstantValue optionsValue =
- value.fields[commonElements.pragmaClassOptionsField];
- if (name == 'dart2js:noInline') {
- if (!optionsValue.isNull) {
- reporter.reportErrorMessage(element, MessageKind.GENERIC,
- {'text': "@pragma('$name') annotation does not take options"});
- }
- hasNoInline = true;
- } else if (name == 'dart2js:tryInline') {
- if (!optionsValue.isNull) {
- reporter.reportErrorMessage(element, MessageKind.GENERIC,
- {'text': "@pragma('$name') annotation does not take options"});
- }
- hasTryInline = true;
- } else if (!platformAnnotationsAllowed) {
- reporter.reportErrorMessage(element, MessageKind.GENERIC,
- {'text': "Unknown dart2js pragma @pragma('$name')"});
- } else {
- // Handle platform-only `@pragma` annotations.
+ } else if (cls == commonElements.noInlineClass) {
+ hasNoInline = true;
+ } else if (cls == commonElements.noThrowsClass) {
+ hasNoThrows = true;
+ bool isValid = true;
+ if (method.isTopLevel) {
+ isValid = true;
+ } else if (method.isStatic) {
+ isValid = true;
+ } else if (method is ConstructorEntity && method.isFactoryConstructor) {
+ isValid = true;
}
+ if (!isValid) {
+ reporter.internalError(
+ method,
+ "@NoThrows() is currently limited to top-level"
+ " or static functions and factory constructors.");
+ }
+ annotationsDataBuilder.registerCannotThrow(method);
+ } else if (cls == commonElements.noSideEffectsClass) {
+ hasNoSideEffects = true;
+ annotationsDataBuilder.registerSideEffectsFree(method);
}
}
- if (hasTryInline && hasNoInline) {
- reporter.reportErrorMessage(element, MessageKind.GENERIC,
- {'text': '@tryInline must not be used with @noInline.'});
- hasTryInline = false;
- }
- if (hasNoInline) {
- annotationsDataBuilder.markAsNonInlinable(method);
- }
- if (hasTryInline) {
- annotationsDataBuilder.markAsTryInline(method);
- }
- if (hasNoThrows && !hasNoInline) {
- reporter.internalError(
- method, "@NoThrows() should always be combined with @noInline.");
- }
- if (hasNoSideEffects && !hasNoInline) {
- reporter.internalError(
- method, "@NoSideEffects() should always be combined with @noInline.");
+ if (cls == commonElements.expectNoInlineClass) {
+ hasNoInline = true;
+ } else if (cls == commonElements.metaNoInlineClass) {
+ hasNoInline = true;
+ } else if (cls == commonElements.metaTryInlineClass) {
+ hasTryInline = true;
+ } else if (cls == commonElements.pragmaClass) {
+ // Recognize:
+ //
+ // @pragma('dart2js:noInline')
+ // @pragma('dart2js:tryInline')
+ //
+ ConstantValue nameValue =
+ value.fields[commonElements.pragmaClassNameField];
+ if (nameValue == null || !nameValue.isString) continue;
+ String name = (nameValue as StringConstantValue).stringValue;
+ if (!name.startsWith('dart2js:')) continue;
+
+ ConstantValue optionsValue =
+ value.fields[commonElements.pragmaClassOptionsField];
+ if (name == 'dart2js:noInline') {
+ if (!optionsValue.isNull) {
+ reporter.reportErrorMessage(element, MessageKind.GENERIC,
+ {'text': "@pragma('$name') annotation does not take options"});
+ }
+ hasNoInline = true;
+ } else if (name == 'dart2js:tryInline') {
+ if (!optionsValue.isNull) {
+ reporter.reportErrorMessage(element, MessageKind.GENERIC,
+ {'text': "@pragma('$name') annotation does not take options"});
+ }
+ hasTryInline = true;
+ } else if (!platformAnnotationsAllowed) {
+ reporter.reportErrorMessage(element, MessageKind.GENERIC,
+ {'text': "Unknown dart2js pragma @pragma('$name')"});
+ } else {
+ // Handle platform-only `@pragma` annotations.
+ if (name == 'dart2js:disableFinal') {
+ if (!optionsValue.isNull) {
+ reporter.reportErrorMessage(element, MessageKind.GENERIC,
+ {'text': "@pragma('$name') annotation does not take options"});
+ }
+ disableFinal = true;
+ }
+ }
}
}
- for (MemberEntity entity in processedMembers) {
- processMemberAnnotations(entity);
+ if (hasTryInline && hasNoInline) {
+ reporter.reportErrorMessage(element, MessageKind.GENERIC,
+ {'text': '@tryInline must not be used with @noInline.'});
+ hasTryInline = false;
}
-
- return annotationsDataBuilder;
+ if (hasNoInline) {
+ values.add(PragmaAnnotation.noInline);
+ annotationsDataBuilder.markAsNonInlinable(method);
+ }
+ if (hasTryInline) {
+ values.add(PragmaAnnotation.tryInline);
+ annotationsDataBuilder.markAsTryInline(method);
+ }
+ if (disableFinal) {
+ values.add(PragmaAnnotation.disableFinal);
+ annotationsDataBuilder.markAsDisableFinal(method);
+ }
+ if (hasNoThrows && !hasNoInline) {
+ reporter.internalError(
+ method, "@NoThrows() should always be combined with @noInline.");
+ }
+ if (hasNoSideEffects && !hasNoInline) {
+ reporter.internalError(
+ method, "@NoSideEffects() should always be combined with @noInline.");
+ }
+ return values;
}
abstract class AnnotationsData {
@@ -187,12 +205,17 @@
/// Serializes this [AnnotationsData] to [sink].
void writeToDataSink(DataSink sink);
- /// Functions with a `@NoInline()` or `@noInline` annotation.
+ /// Functions with a `@NoInline()`, `@noInline`, or
+ /// `@pragma('dart2js:noInline')` annotation.
Iterable<FunctionEntity> get nonInlinableFunctions;
- /// Functions with a `@ForceInline()` or `@tryInline` annotation.
+ /// Functions with a `@ForceInline()`, `@tryInline`, or
+ /// `@pragma('dart2js:tryInline')` annotation.
Iterable<FunctionEntity> get tryInlineFunctions;
+ /// Functions with a `@pragma('dart2js:disable-final')` annotation.
+ Iterable<FunctionEntity> get disableFinalFunctions;
+
/// Functions with a `@NoThrows()` annotation.
Iterable<FunctionEntity> get cannotThrowFunctions;
@@ -213,6 +236,7 @@
final Iterable<FunctionEntity> nonInlinableFunctions;
final Iterable<FunctionEntity> tryInlineFunctions;
+ final Iterable<FunctionEntity> disableFinalFunctions;
final Iterable<FunctionEntity> cannotThrowFunctions;
final Iterable<FunctionEntity> sideEffectFreeFunctions;
final Iterable<MemberEntity> trustTypeAnnotationsMembers;
@@ -221,6 +245,7 @@
AnnotationsDataImpl(
this.nonInlinableFunctions,
this.tryInlineFunctions,
+ this.disableFinalFunctions,
this.cannotThrowFunctions,
this.sideEffectFreeFunctions,
this.trustTypeAnnotationsMembers,
@@ -228,16 +253,32 @@
factory AnnotationsDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
- Iterable<FunctionEntity> nonInlinableFunctions = source.readMembers();
- Iterable<FunctionEntity> tryInlineFunctions = source.readMembers();
- Iterable<FunctionEntity> cannotThrowFunctions = source.readMembers();
- Iterable<FunctionEntity> sideEffectFreeFunctions = source.readMembers();
- Iterable<MemberEntity> trustTypeAnnotationsMembers = source.readMembers();
- Iterable<MemberEntity> assumeDynamicMembers = source.readMembers();
+ Iterable<FunctionEntity> nonInlinableFunctions =
+ source.readMembers<FunctionEntity>(emptyAsNull: true) ??
+ const <FunctionEntity>[];
+ Iterable<FunctionEntity> tryInlineFunctions =
+ source.readMembers<FunctionEntity>(emptyAsNull: true) ??
+ const <FunctionEntity>[];
+ Iterable<FunctionEntity> disableFinalFunctions =
+ source.readMembers<FunctionEntity>(emptyAsNull: true) ??
+ const <FunctionEntity>[];
+ Iterable<FunctionEntity> cannotThrowFunctions =
+ source.readMembers<FunctionEntity>(emptyAsNull: true) ??
+ const <FunctionEntity>[];
+ Iterable<FunctionEntity> sideEffectFreeFunctions =
+ source.readMembers<FunctionEntity>(emptyAsNull: true) ??
+ const <FunctionEntity>[];
+ Iterable<MemberEntity> trustTypeAnnotationsMembers =
+ source.readMembers<MemberEntity>(emptyAsNull: true) ??
+ const <MemberEntity>[];
+ Iterable<MemberEntity> assumeDynamicMembers =
+ source.readMembers<MemberEntity>(emptyAsNull: true) ??
+ const <MemberEntity>[];
source.end(tag);
return new AnnotationsDataImpl(
nonInlinableFunctions,
tryInlineFunctions,
+ disableFinalFunctions,
cannotThrowFunctions,
sideEffectFreeFunctions,
trustTypeAnnotationsMembers,
@@ -248,6 +289,7 @@
sink.begin(tag);
sink.writeMembers(nonInlinableFunctions);
sink.writeMembers(tryInlineFunctions);
+ sink.writeMembers(disableFinalFunctions);
sink.writeMembers(cannotThrowFunctions);
sink.writeMembers(sideEffectFreeFunctions);
sink.writeMembers(trustTypeAnnotationsMembers);
@@ -257,45 +299,63 @@
}
class AnnotationsDataBuilder implements AnnotationsData {
- List<FunctionEntity> _nonInlinableFunctions = <FunctionEntity>[];
- List<FunctionEntity> _tryInlinableFunctions = <FunctionEntity>[];
- List<FunctionEntity> _cannotThrowFunctions = <FunctionEntity>[];
- List<FunctionEntity> _sideEffectFreeFunctions = <FunctionEntity>[];
- List<MemberEntity> _trustTypeAnnotationsMembers = <MemberEntity>[];
- List<MemberEntity> _assumeDynamicMembers = <MemberEntity>[];
+ List<FunctionEntity> _nonInlinableFunctions;
+ List<FunctionEntity> _tryInlinableFunctions;
+ List<FunctionEntity> _disableFinalFunctions;
+ List<FunctionEntity> _cannotThrowFunctions;
+ List<FunctionEntity> _sideEffectFreeFunctions;
+ List<MemberEntity> _trustTypeAnnotationsMembers;
+ List<MemberEntity> _assumeDynamicMembers;
void markAsNonInlinable(FunctionEntity function) {
+ _nonInlinableFunctions ??= <FunctionEntity>[];
_nonInlinableFunctions.add(function);
}
void markAsTryInline(FunctionEntity function) {
+ _tryInlinableFunctions ??= <FunctionEntity>[];
_tryInlinableFunctions.add(function);
}
+ void markAsDisableFinal(FunctionEntity function) {
+ _disableFinalFunctions ??= <FunctionEntity>[];
+ _disableFinalFunctions.add(function);
+ }
+
void registerCannotThrow(FunctionEntity function) {
+ _cannotThrowFunctions ??= <FunctionEntity>[];
_cannotThrowFunctions.add(function);
}
void registerSideEffectsFree(FunctionEntity function) {
+ _sideEffectFreeFunctions ??= <FunctionEntity>[];
_sideEffectFreeFunctions.add(function);
}
void registerTrustTypeAnnotations(MemberEntity member) {
+ _trustTypeAnnotationsMembers ??= <MemberEntity>[];
_trustTypeAnnotationsMembers.add(member);
}
void registerAssumeDynamic(MemberEntity member) {
+ _assumeDynamicMembers ??= <MemberEntity>[];
_assumeDynamicMembers.add(member);
}
- Iterable<FunctionEntity> get nonInlinableFunctions => _nonInlinableFunctions;
- Iterable<FunctionEntity> get tryInlineFunctions => _tryInlinableFunctions;
- Iterable<FunctionEntity> get cannotThrowFunctions => _cannotThrowFunctions;
+ Iterable<FunctionEntity> get nonInlinableFunctions =>
+ _nonInlinableFunctions ?? const <FunctionEntity>[];
+ Iterable<FunctionEntity> get tryInlineFunctions =>
+ _tryInlinableFunctions ?? const <FunctionEntity>[];
+ Iterable<FunctionEntity> get disableFinalFunctions =>
+ _disableFinalFunctions ?? const <FunctionEntity>[];
+ Iterable<FunctionEntity> get cannotThrowFunctions =>
+ _cannotThrowFunctions ?? const <FunctionEntity>[];
Iterable<FunctionEntity> get sideEffectFreeFunctions =>
- _sideEffectFreeFunctions;
+ _sideEffectFreeFunctions ?? const <FunctionEntity>[];
Iterable<MemberEntity> get trustTypeAnnotationsMembers =>
- _trustTypeAnnotationsMembers;
- Iterable<MemberEntity> get assumeDynamicMembers => _assumeDynamicMembers;
+ _trustTypeAnnotationsMembers ?? const <MemberEntity>[];
+ Iterable<MemberEntity> get assumeDynamicMembers =>
+ _assumeDynamicMembers ?? const <MemberEntity>[];
void writeToDataSink(DataSink sink) {
throw new UnsupportedError('AnnotationsDataBuilder.writeToDataSink');
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 22b77c3..1bdea15 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -574,6 +574,8 @@
InterceptorDataBuilder interceptorDataBuilder =
new InterceptorDataBuilderImpl(
nativeBasicData, elementEnvironment, commonElements);
+ AnnotationsDataBuilder annotationsDataBuilder =
+ new AnnotationsDataBuilder();
return new ResolutionEnqueuer(
task,
compiler.options,
@@ -600,12 +602,14 @@
_allocatorResolutionAnalysis,
_nativeResolutionEnqueuer,
noSuchMethodRegistry,
+ annotationsDataBuilder,
const StrongModeWorldStrategy(),
classHierarchyBuilder,
classQueries),
compiler.frontendStrategy.createResolutionWorkItemBuilder(
nativeBasicData,
_nativeDataBuilder,
+ annotationsDataBuilder,
impactTransformer,
compiler.impactCache));
}
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 5110d31..b3ad9ca 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -198,6 +198,8 @@
map.toBackendFunctionSet(
closedWorld.annotationsData.tryInlineFunctions),
map.toBackendFunctionSet(
+ closedWorld.annotationsData.disableFinalFunctions),
+ map.toBackendFunctionSet(
closedWorld.annotationsData.cannotThrowFunctions),
map.toBackendFunctionSet(
closedWorld.annotationsData.sideEffectFreeFunctions),
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 5ea5049..d15fb43 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -35,6 +35,7 @@
import '../ir/visitors.dart';
import '../ir/util.dart';
import '../js/js.dart' as js;
+import '../js_backend/annotations.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/constant_system_javascript.dart';
import '../js_backend/namer.dart';
@@ -1337,11 +1338,13 @@
commonElements, nativeBasicData, reporter, options);
ResolutionImpact computeWorldImpact(
- KMember member, VariableScopeModel variableScopeModel) {
+ KMember member,
+ VariableScopeModel variableScopeModel,
+ Set<PragmaAnnotation> annotations) {
KMemberData memberData = members.getData(member);
ir.Member node = memberData.node;
KernelImpactBuilder builder = new KernelImpactBuilder(
- this, member, reporter, options, variableScopeModel);
+ this, member, reporter, options, variableScopeModel, annotations);
node.accept(builder);
memberData.staticTypes = builder.cachedStaticTypes;
return builder.impactBuilder;
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 431c832..ee62aa6 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -17,6 +17,7 @@
import '../ir/scope.dart';
import '../ir/static_type.dart';
import '../ir/util.dart';
+import '../js_backend/annotations.dart';
import '../js_backend/native_data.dart';
import '../options.dart';
import '../resolution/registry.dart' show ResolutionWorldImpactBuilder;
@@ -35,9 +36,10 @@
final CompilerOptions _options;
final MemberEntity currentMember;
final VariableScopeModel variableScopeModel;
+ final Set<PragmaAnnotation> _annotations;
KernelImpactBuilder(this.elementMap, this.currentMember, this.reporter,
- this._options, this.variableScopeModel)
+ this._options, this.variableScopeModel, this._annotations)
: this.impactBuilder =
new ResolutionWorldImpactBuilder('${currentMember}'),
super(elementMap.typeEnvironment);
@@ -48,6 +50,9 @@
bool get useAsserts => _options.enableUserAssertions;
+ bool get inferEffectivelyFinalVariableTypes =>
+ !_annotations.contains(PragmaAnnotation.disableFinal);
+
/// Add a checked-mode type use of [type] if it is not `dynamic`.
DartType checkType(ir.DartType irType, TypeUseKind kind) {
DartType type = elementMap.getDartType(irType);
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 31c810f..32d2c7a 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -19,6 +19,7 @@
import '../frontend_strategy.dart';
import '../ir/closure.dart' show ClosureScopeModel;
import '../ir/scope.dart' show ScopeModel;
+import '../js_backend/annotations.dart';
import '../js_backend/allocator_analysis.dart' show KAllocatorAnalysis;
import '../js_backend/backend_usage.dart';
import '../js_backend/interceptor_data.dart';
@@ -114,6 +115,7 @@
KAllocatorAnalysis allocatorAnalysis,
NativeResolutionEnqueuer nativeResolutionEnqueuer,
NoSuchMethodRegistry noSuchMethodRegistry,
+ AnnotationsDataBuilder annotationsDataBuilder,
SelectorConstraintsStrategy selectorConstraintsStrategy,
ClassHierarchyBuilder classHierarchyBuilder,
ClassQueries classQueries) {
@@ -131,6 +133,7 @@
allocatorAnalysis,
nativeResolutionEnqueuer,
noSuchMethodRegistry,
+ annotationsDataBuilder,
selectorConstraintsStrategy,
classHierarchyBuilder,
classQueries);
@@ -140,10 +143,18 @@
WorkItemBuilder createResolutionWorkItemBuilder(
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
+ AnnotationsDataBuilder annotationsDataBuilder,
ImpactTransformer impactTransformer,
Map<Entity, WorldImpact> impactCache) {
- return new KernelWorkItemBuilder(_compilerTask, elementMap, nativeBasicData,
- nativeDataBuilder, impactTransformer, closureModels, impactCache);
+ return new KernelWorkItemBuilder(
+ _compilerTask,
+ elementMap,
+ nativeBasicData,
+ nativeDataBuilder,
+ annotationsDataBuilder,
+ impactTransformer,
+ closureModels,
+ impactCache);
}
ClassQueries createClassQueries() {
@@ -161,6 +172,7 @@
final KernelToElementMapImpl _elementMap;
final ImpactTransformer _impactTransformer;
final NativeMemberResolver _nativeMemberResolver;
+ final AnnotationsDataBuilder _annotationsDataBuilder;
final Map<MemberEntity, ClosureScopeModel> closureModels;
final Map<Entity, WorldImpact> impactCache;
@@ -169,6 +181,7 @@
this._elementMap,
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
+ this._annotationsDataBuilder,
this._impactTransformer,
this.closureModels,
this.impactCache)
@@ -177,8 +190,15 @@
@override
WorkItem createWorkItem(MemberEntity entity) {
- return new KernelWorkItem(_compilerTask, _elementMap, _impactTransformer,
- _nativeMemberResolver, entity, closureModels, impactCache);
+ return new KernelWorkItem(
+ _compilerTask,
+ _elementMap,
+ _impactTransformer,
+ _nativeMemberResolver,
+ _annotationsDataBuilder,
+ entity,
+ closureModels,
+ impactCache);
}
}
@@ -187,6 +207,7 @@
final KernelToElementMapImpl _elementMap;
final ImpactTransformer _impactTransformer;
final NativeMemberResolver _nativeMemberResolver;
+ final AnnotationsDataBuilder _annotationsDataBuilder;
final MemberEntity element;
final Map<MemberEntity, ClosureScopeModel> closureModels;
final Map<Entity, WorldImpact> impactCache;
@@ -196,6 +217,7 @@
this._elementMap,
this._impactTransformer,
this._nativeMemberResolver,
+ this._annotationsDataBuilder,
this.element,
this.closureModels,
this.impactCache);
@@ -204,6 +226,12 @@
WorldImpact run() {
return _compilerTask.measure(() {
_nativeMemberResolver.resolveNativeMember(element);
+ Set<PragmaAnnotation> annotations = processMemberAnnotations(
+ _elementMap.reporter,
+ _elementMap.commonElements,
+ _elementMap.elementEnvironment,
+ _annotationsDataBuilder,
+ element);
ScopeModel scopeModel = _compilerTask.measureSubtask('closures', () {
ScopeModel scopeModel = _elementMap.computeScopeModel(element);
if (scopeModel?.closureScopeModel != null) {
@@ -213,7 +241,7 @@
});
return _compilerTask.measureSubtask('worldImpact', () {
ResolutionImpact impact = _elementMap.computeWorldImpact(
- element, scopeModel?.variableScopeModel);
+ element, scopeModel?.variableScopeModel, annotations);
WorldImpact worldImpact =
_impactTransformer.transformResolutionImpact(impact);
if (impactCache != null) {
diff --git a/pkg/compiler/lib/src/serialization/member_data.dart b/pkg/compiler/lib/src/serialization/member_data.dart
index 69bb187..b4aeee12 100644
--- a/pkg/compiler/lib/src/serialization/member_data.dart
+++ b/pkg/compiler/lib/src/serialization/member_data.dart
@@ -21,7 +21,9 @@
_libraryMap[library.importUri] = new _LibraryData(library);
}
}
- return _libraryMap[canonicalUri];
+ _LibraryData data = _libraryMap[canonicalUri];
+ assert(data != null, "No library found for $canonicalUri.");
+ return data;
}
}
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 39caad3..6e75f80 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -399,6 +399,7 @@
final KAllocatorAnalysis _allocatorAnalysis;
final NativeResolutionEnqueuer _nativeResolutionEnqueuer;
final NoSuchMethodRegistry _noSuchMethodRegistry;
+ final AnnotationsDataBuilder _annotationsDataBuilder;
final SelectorConstraintsStrategy _selectorConstraintsStrategy;
final ClassHierarchyBuilder _classHierarchyBuilder;
@@ -435,6 +436,7 @@
this._allocatorAnalysis,
this._nativeResolutionEnqueuer,
this._noSuchMethodRegistry,
+ this._annotationsDataBuilder,
this._selectorConstraintsStrategy,
this._classHierarchyBuilder,
this._classQueries);
@@ -1024,9 +1026,6 @@
BackendUsage backendUsage = _backendUsageBuilder.close();
_closed = true;
- AnnotationsData annotationsData = processAnnotations(
- reporter, _commonElements, _elementEnvironment, _processedMembers);
-
KClosedWorld closedWorld = new KClosedWorldImpl(_elementMap,
options: _options,
elementEnvironment: _elementEnvironment,
@@ -1047,7 +1046,7 @@
mixinUses: _classHierarchyBuilder.mixinUses,
typesImplementedBySubclasses: typesImplementedBySubclasses,
classHierarchy: _classHierarchyBuilder.close(),
- annotationsData: annotationsData);
+ annotationsData: _annotationsDataBuilder);
if (retainDataForTesting) {
_closedWorldCache = closedWorld;
}
diff --git a/tests/compiler/dart2js/analyses/analysis_helper.dart b/tests/compiler/dart2js/analyses/analysis_helper.dart
index fec52d9..9fcd366 100644
--- a/tests/compiler/dart2js/analyses/analysis_helper.dart
+++ b/tests/compiler/dart2js/analyses/analysis_helper.dart
@@ -79,6 +79,9 @@
bool get useAsserts => false;
@override
+ bool get inferEffectivelyFinalVariableTypes => true;
+
+ @override
Null visitProcedure(ir.Procedure node) {
if (node.kind == ir.ProcedureKind.Factory) {
if (node.function.body is ir.RedirectingFactoryBody) {
diff --git a/tests/compiler/dart2js/rti/data/as.dart b/tests/compiler/dart2js/rti/data/as.dart
index 6f2de47..b84f239 100644
--- a/tests/compiler/dart2js/rti/data/as.dart
+++ b/tests/compiler/dart2js/rti/data/as.dart
@@ -15,6 +15,7 @@
/*class: Baz:explicit=[Baz<num>],needsArgs*/
class Baz<T extends num> {}
+@pragma('dart2js:disableFinal')
main() {
test(new Foo(), Foo, expectTypeArguments: false);
// ignore: unnecessary_cast
@@ -22,9 +23,6 @@
Baz<num> b = new Baz();
dynamic c = b;
test(c as Baz<num>, Baz, expectTypeArguments: true);
- // Makes sure that [c] is not effectively final, so that we don't infer the
- // static type from the initializer.
- c = null;
}
void test(dynamic object, Type type, {bool expectTypeArguments}) {
diff --git a/tests/compiler/dart2js_extra/35341_test.dart b/tests/compiler/dart2js_extra/35341_test.dart
index c19ca81..027182f 100644
--- a/tests/compiler/dart2js_extra/35341_test.dart
+++ b/tests/compiler/dart2js_extra/35341_test.dart
@@ -6,11 +6,9 @@
import "dart:async";
+@pragma('dart2js:disableFinal')
void main() {
FutureOr<int> i = 0;
i = new Future<int>.value(0);
print(i.runtimeType);
- // Ensure that [i] is not effectively final, so that we don't infer the
- // static type from the initializer.
- i = null;
}
diff --git a/tests/compiler/dart2js_extra/881_test.dart b/tests/compiler/dart2js_extra/881_test.dart
index dfc9577..5be849c 100644
--- a/tests/compiler/dart2js_extra/881_test.dart
+++ b/tests/compiler/dart2js_extra/881_test.dart
@@ -4,10 +4,8 @@
// Regression test for DartPad issue 881.
+@pragma('dart2js:disableFinal')
void main() {
String v = null;
print('${v.hashCode}');
- // Makes sure that [v] is not effectively final, so that we don't infer the
- // static type from the initializer.
- v = '';
}
diff --git a/tests/compiler/dart2js_extra/generic_type_error_message_test.dart b/tests/compiler/dart2js_extra/generic_type_error_message_test.dart
index d331999..038fecf 100644
--- a/tests/compiler/dart2js_extra/generic_type_error_message_test.dart
+++ b/tests/compiler/dart2js_extra/generic_type_error_message_test.dart
@@ -12,15 +12,13 @@
class Baz<T extends num> {}
+@pragma('dart2js:disableFinal')
main() {
test(new Foo(), Foo, expectTypeArguments: false);
test(new Bar() as Bar<num>, Bar, expectTypeArguments: false);
Baz<num> b = new Baz();
dynamic c = b;
test(c as Baz<num>, Baz, expectTypeArguments: true);
- // Makes sure that [c] is not effectively final, so that we don't infer the
- // static type from the initializer.
- c = null;
}
void test(dynamic object, Type type, {bool expectTypeArguments}) {