blob: 0d91e034bac635d0ccb0bea1a1454593d5bf3f67 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.universe.world_impact;
import '../elements/entities.dart';
import '../util/util.dart' show Setlet;
import 'use.dart';
/// Describes how an element (e.g. a method) impacts the closed-world
/// semantics of a program.
///
/// A [WorldImpact] contains information about how a program element affects our
/// understanding of what's live in a program. For example, it can indicate
/// that a method uses a certain feature, or allocates a specific type.
///
/// The impact object can be computed locally by inspecting just the resolution
/// information of that element alone. The compiler uses [Universe] and
/// [World] to combine the information discovered in the impact objects of
/// all elements reachable in an application.
class WorldImpact {
const WorldImpact();
/// [member] may be `null` when the impact is for something that is not a
/// member, e.g. a constant, or external or native dependencies.
MemberEntity? get member => null;
Iterable<DynamicUse> get dynamicUses => const [];
Iterable<StaticUse> get staticUses => const [];
// TODO(johnniwinther): Replace this by called constructors with type
// arguments.
// TODO(johnniwinther): Collect all checked types for checked mode separately
// to support serialization.
Iterable<TypeUse> get typeUses => const [];
Iterable<ConstantUse> get constantUses => const [];
void _forEach<U>(
Iterable<U> uses, void Function(MemberEntity?, U) visitUse) =>
uses.forEach((use) => visitUse(member, use));
void forEachDynamicUse(void Function(MemberEntity?, DynamicUse) visitUse) =>
_forEach(dynamicUses, visitUse);
void forEachStaticUse(void Function(MemberEntity?, StaticUse) visitUse) =>
_forEach(staticUses, visitUse);
void forEachTypeUse(void Function(MemberEntity?, TypeUse) visitUse) =>
_forEach(typeUses, visitUse);
void forEachConstantUse(void Function(MemberEntity?, ConstantUse) visitUse) =>
_forEach(constantUses, visitUse);
bool get isEmpty => true;
@override
String toString() => dump(this);
static String dump(WorldImpact worldImpact) {
StringBuffer sb = StringBuffer();
printOn(sb, worldImpact);
return sb.toString();
}
static void printOn(StringBuffer sb, WorldImpact worldImpact) {
sb.write('member: ${worldImpact.member}');
void add(String title, Iterable iterable) {
if (iterable.isNotEmpty) {
sb.write('\n $title:');
iterable.forEach((e) => sb.write('\n $e'));
}
}
add('dynamic uses', worldImpact.dynamicUses);
add('static uses', worldImpact.staticUses);
add('type uses', worldImpact.typeUses);
add('constant uses', worldImpact.constantUses);
}
}
abstract class WorldImpactBuilder extends WorldImpact {
void registerDynamicUse(DynamicUse dynamicUse);
void registerTypeUse(TypeUse typeUse);
void registerStaticUse(StaticUse staticUse);
void registerConstantUse(ConstantUse constantUse);
}
class WorldImpactBuilderImpl extends WorldImpactBuilder {
/// The [MemberEntity] associated with this set of impacts. Maybe null.
@override
final MemberEntity? member;
// TODO(johnniwinther): Do we benefit from lazy initialization of the
// [Setlet]s?
Set<DynamicUse>? _dynamicUses;
Set<StaticUse>? _staticUses;
Set<TypeUse>? _typeUses;
Set<ConstantUse>? _constantUses;
WorldImpactBuilderImpl([this.member]);
WorldImpactBuilderImpl.internal(
this._dynamicUses, this._staticUses, this._typeUses, this._constantUses,
{this.member});
@override
bool get isEmpty =>
_dynamicUses == null &&
_staticUses == null &&
_typeUses == null &&
_constantUses == null;
/// Copy uses in [impact] to this impact builder.
void addImpact(WorldImpact impact) {
if (impact.isEmpty) return;
impact.dynamicUses.forEach(registerDynamicUse);
impact.staticUses.forEach(registerStaticUse);
impact.typeUses.forEach(registerTypeUse);
impact.constantUses.forEach(registerConstantUse);
}
@override
void registerDynamicUse(DynamicUse dynamicUse) {
assert((dynamicUse as dynamic) != null); // TODO(48820): Remove when sound.
(_dynamicUses ??= Setlet()).add(dynamicUse);
}
@override
Iterable<DynamicUse> get dynamicUses {
return _dynamicUses ?? const [];
}
@override
void registerTypeUse(TypeUse typeUse) {
assert((typeUse as dynamic) != null); // TODO(48820): Remove when sound.
(_typeUses ??= Setlet()).add(typeUse);
}
@override
Iterable<TypeUse> get typeUses {
return _typeUses ?? const [];
}
@override
void registerStaticUse(StaticUse staticUse) {
assert((staticUse as dynamic) != null); // TODO(48820): Remove when sound.
(_staticUses ??= Setlet()).add(staticUse);
}
@override
Iterable<StaticUse> get staticUses {
return _staticUses ?? const [];
}
@override
void registerConstantUse(ConstantUse constantUse) {
assert((constantUse as dynamic) != null); // TODO(48820): Remove when sound.
(_constantUses ??= Setlet()).add(constantUse);
}
@override
Iterable<ConstantUse> get constantUses {
return _constantUses ?? const [];
}
}
/// Mutable implementation of [WorldImpact] used to transform
/// [ResolutionImpact] or [CodegenImpact] to [WorldImpact].
class TransformedWorldImpact extends WorldImpactBuilder {
final WorldImpact worldImpact;
Setlet<StaticUse>? _staticUses;
Setlet<TypeUse>? _typeUses;
Setlet<DynamicUse>? _dynamicUses;
Setlet<ConstantUse>? _constantUses;
TransformedWorldImpact(this.worldImpact);
@override
MemberEntity? get member => worldImpact.member;
@override
bool get isEmpty {
return worldImpact.isEmpty &&
_staticUses == null &&
_typeUses == null &&
_dynamicUses == null &&
_constantUses == null;
}
@override
Iterable<DynamicUse> get dynamicUses {
return _dynamicUses ?? worldImpact.dynamicUses;
}
@override
void registerDynamicUse(DynamicUse dynamicUse) {
_dynamicUses ??= Setlet.of(worldImpact.dynamicUses);
_dynamicUses!.add(dynamicUse);
}
@override
void registerTypeUse(TypeUse typeUse) {
_typeUses ??= Setlet.of(worldImpact.typeUses);
_typeUses!.add(typeUse);
}
@override
Iterable<TypeUse> get typeUses {
return _typeUses ?? worldImpact.typeUses;
}
@override
void registerStaticUse(StaticUse staticUse) {
_staticUses ??= Setlet.of(worldImpact.staticUses);
_staticUses!.add(staticUse);
}
@override
Iterable<StaticUse> get staticUses {
return _staticUses ?? worldImpact.staticUses;
}
@override
Iterable<ConstantUse> get constantUses {
return _constantUses ?? worldImpact.constantUses;
}
@override
void registerConstantUse(ConstantUse constantUse) {
_constantUses ??= Setlet.of(worldImpact.constantUses);
_constantUses!.add(constantUse);
}
@override
String toString() {
StringBuffer sb = StringBuffer();
sb.write('TransformedWorldImpact($worldImpact)');
WorldImpact.printOn(sb, this);
return sb.toString();
}
}