blob: e32f17967c21f3dd1c148c6437ec77062d8074f7 [file] [log] [blame]
// Copyright (c) 2019, 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 fasta.transform_set_literals;
import 'dart:core' hide MapEntry;
import 'package:kernel/ast.dart'
show
Arguments,
Class,
Constructor,
ConstructorInvocation,
DartType,
Expression,
InterfaceType,
Let,
Library,
MapEntry,
MapLiteral,
MethodInvocation,
Name,
NullLiteral,
Procedure,
SetLiteral,
StaticInvocation,
TreeNode,
VariableDeclaration,
VariableGet;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/visitor.dart' show Transformer;
import '../source/source_loader.dart' show SourceLoader;
import 'redirecting_factory_body.dart' show RedirectingFactoryBody;
// TODO(askesc): Delete this class when all backends support set literals.
class SetLiteralTransformer extends Transformer {
final CoreTypes coreTypes;
final DartType nullType;
final Procedure setFactory;
final Procedure addMethod;
final Constructor unmodifiableSetConstructor;
static Procedure _findSetFactory(CoreTypes coreTypes) {
Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
RedirectingFactoryBody body = factory?.function?.body;
return body?.target;
}
static Procedure _findAddMethod(CoreTypes coreTypes) {
return coreTypes.index.getMember('dart:core', 'Set', 'add');
}
static Constructor _findUnmodifiableSetConstructor(
SourceLoader<Library> loader) {
// We should not generally dig into libraries like this, and we should
// avoid dependencies on libraries other than the ones indexed by
// CoreTypes. This is a temporary solution until all backends have
// implemented support for set literals.
Uri collectionUri = Uri.parse("dart:collection");
Library collectionLibrary = loader.builders[collectionUri].target;
for (int i = 0; i < collectionLibrary.classes.length; i++) {
Class classNode = collectionLibrary.classes[i];
if (classNode.name == "_UnmodifiableSet") {
for (int j = 0; j < collectionLibrary.classes.length; j++) {
Constructor constructor = classNode.constructors[j];
if (constructor.name.name.isEmpty) {
return constructor;
}
}
}
}
return null;
}
SetLiteralTransformer(SourceLoader<Library> loader)
: coreTypes = loader.coreTypes,
nullType = new InterfaceType(loader.coreTypes.nullClass, []),
setFactory = _findSetFactory(loader.coreTypes),
addMethod = _findAddMethod(loader.coreTypes),
unmodifiableSetConstructor = _findUnmodifiableSetConstructor(loader);
TreeNode visitSetLiteral(SetLiteral node) {
if (node.isConst) {
List<MapEntry> entries = new List<MapEntry>(node.expressions.length);
for (int i = 0; i < node.expressions.length; i++) {
// expression_i: null
Expression entry = node.expressions[i].accept(this);
entries[i] = new MapEntry(entry, new NullLiteral());
}
Expression mapExp = new MapLiteral(entries,
keyType: node.typeArgument, valueType: nullType, isConst: true);
return new ConstructorInvocation(unmodifiableSetConstructor,
new Arguments([mapExp], types: [node.typeArgument]),
isConst: true);
} else {
// Outermost declaration of let chain: Set<E> setVar = new Set<E>();
VariableDeclaration setVar = new VariableDeclaration.forValue(
new StaticInvocation(
setFactory, new Arguments([], types: [node.typeArgument])),
type: new InterfaceType(coreTypes.setClass, [node.typeArgument]));
// Innermost body of let chain: setVar
Expression setExp = new VariableGet(setVar);
for (int i = node.expressions.length - 1; i >= 0; i--) {
// let _ = setVar.add(expression) in rest
Expression entry = node.expressions[i].accept(this);
setExp = new Let(
new VariableDeclaration.forValue(new MethodInvocation(
new VariableGet(setVar),
new Name("add"),
new Arguments([entry]),
addMethod)),
setExp);
}
return new Let(setVar, setExp);
}
}
}