Skip to content

Commit be815e1

Browse files
Jenny Messerlycommit-bot@chromium.org
Jenny Messerly
authored andcommitted
[dartdevc] fix #35013, move DDC off Analyzer task model
The new file pkg/dev_compiler/lib/src/analyzer/driver.dart handles building the linked summary for a build unit, and then is capable of doing analysis using LibraryAnalyzer. The algorithm is very similar to analyzer_cli's build mode. The biggest difference is that `dartdevc` has existing support for discovering source files from the explicit source list (rather than requiring every source to be listed on the command line). We don't want to break that support, so there's a bit of logic to follow imports, exports, and parts. After the linked summary is produced, DDC gets the analysis results (errors and resolved AST) for each library, and compiles it into a JS module. Change-Id: I7bf1ce1eca73fd036002e498de5924c488b534dc Reviewed-on: https://dart-review.googlesource.com/c/82469 Commit-Queue: Jenny Messerly <[email protected]> Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Vijay Menon <[email protected]>
1 parent d150268 commit be815e1

21 files changed

+799
-557
lines changed

pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,14 @@ class LibraryAnalyzer {
8383
// TODO(brianwilkerson) Determine whether this await is necessary.
8484
await null;
8585
return PerformanceStatistics.analysis.makeCurrentWhileAsync(() async {
86-
return _analyze();
86+
return analyzeSync();
8787
});
8888
}
8989

90-
Map<FileState, UnitAnalysisResult> _analyze() {
90+
/**
91+
* Compute analysis results for all units of the library.
92+
*/
93+
Map<FileState, UnitAnalysisResult> analyzeSync() {
9194
Map<FileState, CompilationUnit> units = {};
9295

9396
// Parse all files.

pkg/dev_compiler/bin/dartdevc.dart

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Future main(List<String> args, [SendPort sendPort]) async {
3838
class _CompilerWorker extends AsyncWorkerLoop {
3939
/// The original args supplied to the executable.
4040
final ParsedArguments _startupArgs;
41-
InitializedCompilerState _compilerState;
41+
CompilerResult _result;
4242

4343
_CompilerWorker(this._startupArgs, AsyncWorkerConnection workerConnection)
4444
: super(connection: workerConnection);
@@ -47,14 +47,13 @@ class _CompilerWorker extends AsyncWorkerLoop {
4747
Future<WorkResponse> performRequest(WorkRequest request) async {
4848
var args = _startupArgs.merge(request.arguments);
4949
var output = StringBuffer();
50-
var result = await runZoned(
51-
() => compile(args, compilerState: _compilerState), zoneSpecification:
50+
_result = await runZoned(() => compile(args, previousResult: _result),
51+
zoneSpecification:
5252
ZoneSpecification(print: (self, parent, zone, message) {
5353
output.writeln(message.toString());
5454
}));
55-
_compilerState = result.compilerState;
5655
return WorkResponse()
57-
..exitCode = result.success ? 0 : 1
56+
..exitCode = _result.success ? 0 : 1
5857
..output = output.toString();
5958
}
6059
}
@@ -68,16 +67,15 @@ Future runBatch(ParsedArguments batchArgs) async {
6867
print('>>> BATCH START');
6968

7069
String line;
71-
InitializedCompilerState compilerState;
70+
CompilerResult result;
7271

7372
while ((line = stdin.readLineSync(encoding: utf8))?.isNotEmpty == true) {
7473
totalTests++;
7574
var args = batchArgs.merge(line.split(RegExp(r'\s+')));
7675

7776
String outcome;
7877
try {
79-
var result = await compile(args, compilerState: compilerState);
80-
compilerState = result.compilerState;
78+
result = await compile(args, previousResult: result);
8179
outcome = result.success ? 'PASS' : (result.crashed ? 'CRASH' : 'FAIL');
8280
} catch (e, s) {
8381
outcome = 'CRASH';

pkg/dev_compiler/lib/src/analyzer/code_generator.dart

Lines changed: 57 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,23 @@ import 'dart:collection' show HashMap, HashSet;
66
import 'dart:math' show min, max;
77

88
import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9+
import 'package:analyzer/dart/analysis/declared_variables.dart';
910
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
1011
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
1112
import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
1213
import 'package:analyzer/dart/element/element.dart';
1314
import 'package:analyzer/dart/element/type.dart';
1415
import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
1516
import 'package:analyzer/src/dart/element/element.dart';
17+
import 'package:analyzer/src/dart/element/handle.dart';
1618
import 'package:analyzer/src/dart/element/type.dart';
17-
import 'package:analyzer/src/dart/sdk/sdk.dart';
1819
import 'package:analyzer/src/generated/constant.dart'
1920
show DartObject, DartObjectImpl;
20-
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
2121
import 'package:analyzer/src/generated/resolver.dart'
2222
show TypeProvider, NamespaceBuilder;
2323
import 'package:analyzer/src/generated/type_system.dart'
2424
show StrongTypeSystemImpl;
25-
import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit;
26-
import 'package:analyzer/src/summary/link.dart' as summary_link;
2725
import 'package:analyzer/src/summary/package_bundle_reader.dart';
28-
import 'package:analyzer/src/summary/summarize_ast.dart'
29-
show serializeAstUnlinked;
30-
import 'package:analyzer/src/summary/summarize_elements.dart'
31-
show PackageBundleAssembler;
32-
import 'package:analyzer/src/summary/summary_sdk.dart';
3326
import 'package:analyzer/src/task/strong/ast_properties.dart';
3427
import 'package:path/path.dart' as path;
3528
import 'package:source_span/source_span.dart' show SourceLocation;
@@ -43,6 +36,7 @@ import '../js_ast/js_ast.dart' as JS;
4336
import '../js_ast/js_ast.dart' show js;
4437
import '../js_ast/source_map_printer.dart' show NodeEnd, NodeSpan, HoverComment;
4538
import 'ast_builder.dart';
39+
import 'driver.dart';
4640
import 'element_helpers.dart';
4741
import 'error_helpers.dart';
4842
import 'extension_types.dart' show ExtensionTypeSet;
@@ -73,7 +67,6 @@ import 'type_utilities.dart';
7367
class CodeGenerator extends Object
7468
with NullableTypeInference, SharedCompiler<LibraryElement>
7569
implements AstVisitor<JS.Node> {
76-
final AnalysisContext context;
7770
final SummaryDataStore summaryData;
7871

7972
final CompilerOptions options;
@@ -200,38 +193,45 @@ class CodeGenerator extends Object
200193

201194
final _usedCovariantPrivateMembers = HashSet<ExecutableElement>();
202195

203-
CodeGenerator(AnalysisContext c, this.summaryData, this.options,
204-
this._extensionTypes, this.errors)
205-
: context = c,
206-
rules = StrongTypeSystemImpl(c.typeProvider),
207-
types = c.typeProvider,
208-
_asyncStreamIterator = getClass(c, 'dart:async', 'StreamIterator').type,
209-
_coreIdentical = _getLibrary(c, 'dart:core')
196+
final DeclaredVariables declaredVariables;
197+
198+
CodeGenerator(LinkedAnalysisDriver driver, this.types, this.summaryData,
199+
this.options, this._extensionTypes, this.errors)
200+
: rules = StrongTypeSystemImpl(types),
201+
declaredVariables = driver.declaredVariables,
202+
_asyncStreamIterator =
203+
driver.getClass('dart:async', 'StreamIterator').type,
204+
_coreIdentical = driver
205+
.getLibrary('dart:core')
210206
.publicNamespace
211207
.get('identical') as FunctionElement,
212-
_jsArray = getClass(c, 'dart:_interceptors', 'JSArray'),
213-
interceptorClass = getClass(c, 'dart:_interceptors', 'Interceptor'),
214-
coreLibrary = _getLibrary(c, 'dart:core'),
215-
boolClass = getClass(c, 'dart:core', 'bool'),
216-
intClass = getClass(c, 'dart:core', 'int'),
217-
doubleClass = getClass(c, 'dart:core', 'double'),
218-
numClass = getClass(c, 'dart:core', 'num'),
219-
nullClass = getClass(c, 'dart:core', 'Null'),
220-
objectClass = getClass(c, 'dart:core', 'Object'),
221-
stringClass = getClass(c, 'dart:core', 'String'),
222-
functionClass = getClass(c, 'dart:core', 'Function'),
223-
privateSymbolClass = getClass(c, 'dart:_js_helper', 'PrivateSymbol'),
208+
_jsArray = driver.getClass('dart:_interceptors', 'JSArray'),
209+
interceptorClass = driver.getClass('dart:_interceptors', 'Interceptor'),
210+
coreLibrary = driver.getLibrary('dart:core'),
211+
boolClass = driver.getClass('dart:core', 'bool'),
212+
intClass = driver.getClass('dart:core', 'int'),
213+
doubleClass = driver.getClass('dart:core', 'double'),
214+
numClass = driver.getClass('dart:core', 'num'),
215+
nullClass = driver.getClass('dart:core', 'Null'),
216+
objectClass = driver.getClass('dart:core', 'Object'),
217+
stringClass = driver.getClass('dart:core', 'String'),
218+
functionClass = driver.getClass('dart:core', 'Function'),
219+
privateSymbolClass =
220+
driver.getClass('dart:_js_helper', 'PrivateSymbol'),
224221
linkedHashMapImplType =
225-
getClass(c, 'dart:_js_helper', 'LinkedMap').type,
222+
driver.getClass('dart:_js_helper', 'LinkedMap').type,
226223
identityHashMapImplType =
227-
getClass(c, 'dart:_js_helper', 'IdentityMap').type,
228-
linkedHashSetImplType = getClass(c, 'dart:collection', '_HashSet').type,
224+
driver.getClass('dart:_js_helper', 'IdentityMap').type,
225+
linkedHashSetImplType =
226+
driver.getClass('dart:collection', '_HashSet').type,
229227
identityHashSetImplType =
230-
getClass(c, 'dart:collection', '_IdentityHashSet').type,
231-
syncIterableType = getClass(c, 'dart:_js_helper', 'SyncIterable').type,
232-
asyncStarImplType = getClass(c, 'dart:async', '_AsyncStarImpl').type,
233-
dartJSLibrary = _getLibrary(c, 'dart:js') {
234-
jsTypeRep = JSTypeRep(rules, c);
228+
driver.getClass('dart:collection', '_IdentityHashSet').type,
229+
syncIterableType =
230+
driver.getClass('dart:_js_helper', 'SyncIterable').type,
231+
asyncStarImplType =
232+
driver.getClass('dart:async', '_AsyncStarImpl').type,
233+
dartJSLibrary = driver.getLibrary('dart:js') {
234+
jsTypeRep = JSTypeRep(rules, driver);
235235
}
236236

237237
LibraryElement get currentLibrary => _currentElement.library;
@@ -248,92 +248,12 @@ class CodeGenerator extends Object
248248
///
249249
/// Takes the metadata for the build unit, as well as resolved trees and
250250
/// errors, and computes the output module code and optionally the source map.
251-
JSModuleFile compile(List<CompilationUnit> compilationUnits) {
251+
JS.Program compile(List<CompilationUnit> compilationUnits) {
252252
_libraryRoot = options.libraryRoot;
253253
if (!_libraryRoot.endsWith(path.separator)) {
254254
_libraryRoot += path.separator;
255255
}
256256

257-
var name = options.moduleName;
258-
invalidModule() =>
259-
JSModuleFile.invalid(name, formatErrors(context, errors), options);
260-
261-
if (!options.unsafeForceCompile && errors.any(_isFatalError)) {
262-
return invalidModule();
263-
}
264-
265-
try {
266-
var module = _emitModule(compilationUnits, name);
267-
if (!options.unsafeForceCompile && errors.any(_isFatalError)) {
268-
return invalidModule();
269-
}
270-
271-
var dartApiSummary = _summarizeModule(compilationUnits);
272-
return JSModuleFile(
273-
name, formatErrors(context, errors), options, module, dartApiSummary);
274-
} catch (e) {
275-
if (errors.any(_isFatalError)) {
276-
// Force compilation failed. Suppress the exception and report
277-
// the static errors instead.
278-
assert(options.unsafeForceCompile);
279-
return invalidModule();
280-
}
281-
rethrow;
282-
}
283-
}
284-
285-
bool _isFatalError(AnalysisError e) {
286-
if (errorSeverity(context, e) != ErrorSeverity.ERROR) return false;
287-
288-
// These errors are not fatal in the REPL compile mode as we
289-
// allow access to private members across library boundaries
290-
// and those accesses will show up as undefined members unless
291-
// additional analyzer changes are made to support them.
292-
// TODO(jacobr): consider checking that the identifier name
293-
// referenced by the error is private.
294-
return !options.replCompile ||
295-
(e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
296-
e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
297-
e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
298-
}
299-
300-
List<int> _summarizeModule(List<CompilationUnit> units) {
301-
if (!options.summarizeApi) return null;
302-
303-
if (!units.any((u) => u.declaredElement.source.isInSystemLibrary)) {
304-
var sdk = context.sourceFactory.dartSdk;
305-
summaryData.addBundle(
306-
null,
307-
sdk is SummaryBasedDartSdk
308-
? sdk.bundle
309-
: (sdk as FolderBasedDartSdk).getSummarySdkBundle());
310-
}
311-
312-
var assembler = PackageBundleAssembler();
313-
314-
var uriToUnit = Map<String, UnlinkedUnit>.fromIterables(
315-
units.map((u) => u.declaredElement.source.uri.toString()),
316-
units.map((unit) {
317-
var unlinked = serializeAstUnlinked(unit);
318-
assembler.addUnlinkedUnit(unit.declaredElement.source, unlinked);
319-
return unlinked;
320-
}));
321-
322-
summary_link
323-
.link(
324-
uriToUnit.keys.toSet(),
325-
(uri) => summaryData.linkedMap[uri],
326-
(uri) => summaryData.unlinkedMap[uri] ?? uriToUnit[uri],
327-
context.declaredVariables.get)
328-
.forEach(assembler.addLinkedLibrary);
329-
330-
var bundle = assembler.assemble();
331-
// Preserve only API-level information in the summary.
332-
bundle.flushInformative();
333-
return bundle.toBuffer();
334-
}
335-
336-
JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) {
337257
if (moduleItems.isNotEmpty) {
338258
throw StateError('Can only call emitModule once.');
339259
}
@@ -388,7 +308,7 @@ class CodeGenerator extends Object
388308

389309
// Collect all class/type Element -> Node mappings
390310
// in case we need to forward declare any classes.
391-
_declarationNodes = HashMap<TypeDefiningElement, AstNode>.identity();
311+
_declarationNodes = HashMap<TypeDefiningElement, AstNode>();
392312
for (var unit in compilationUnits) {
393313
for (var declaration in unit.declarations) {
394314
var element = declaration.declaredElement;
@@ -398,7 +318,7 @@ class CodeGenerator extends Object
398318
}
399319
}
400320
if (compilationUnits.isNotEmpty) {
401-
_constants = ConstFieldVisitor(context,
321+
_constants = ConstFieldVisitor(types, declaredVariables,
402322
dummySource: resolutionMap
403323
.elementDeclaredByCompilationUnit(compilationUnits.first)
404324
.source);
@@ -430,7 +350,7 @@ class CodeGenerator extends Object
430350
items.add(js.statement('const # = #;', [id, value]));
431351
});
432352

433-
_emitDebuggerExtensionInfo(name);
353+
_emitDebuggerExtensionInfo(options.moduleName);
434354

435355
// Discharge the type table cache variables and
436356
// hoisted definitions.
@@ -638,7 +558,7 @@ class CodeGenerator extends Object
638558
void _declareBeforeUse(TypeDefiningElement e) {
639559
if (e == null) return;
640560

641-
if (_topLevelClass != null && identical(_currentElement, _topLevelClass)) {
561+
if (_topLevelClass != null && _currentElement == _topLevelClass) {
642562
// If the item is from our library, try to emit it now.
643563
_emitTypeDeclaration(e);
644564
}
@@ -2147,7 +2067,7 @@ class CodeGenerator extends Object
21472067
var extMembers = _classProperties.extensionMethods;
21482068
var staticMethods = <JS.Property>[];
21492069
var instanceMethods = <JS.Property>[];
2150-
var classMethods = classElem.methods.where((m) => !m.isAbstract).toList();
2070+
var classMethods = List.of(classElem.methods.where((m) => !m.isAbstract));
21512071
for (var m in mockMembers.values) {
21522072
if (m is MethodElement) classMethods.add(m);
21532073
}
@@ -2327,8 +2247,11 @@ class CodeGenerator extends Object
23272247
if (!element.parameters.any(_isCovariant)) return element.type;
23282248

23292249
var parameters = element.parameters
2330-
.map((p) => ParameterElementImpl.synthetic(p.name,
2331-
_isCovariant(p) ? objectClass.type : p.type, p.parameterKind))
2250+
.map((p) => ParameterElementImpl.synthetic(
2251+
p.name,
2252+
// ignore: deprecated_member_use
2253+
_isCovariant(p) ? objectClass.type : p.type,
2254+
p.parameterKind))
23322255
.toList();
23332256

23342257
var function = FunctionElementImpl("", -1)
@@ -4983,8 +4906,8 @@ class CodeGenerator extends Object
49834906

49844907
variable ??= JS.TemporaryId(name);
49854908

4986-
var idElement = TemporaryVariableElement.forNode(id, variable)
4987-
..enclosingElement = _currentElement;
4909+
var idElement =
4910+
TemporaryVariableElement.forNode(id, variable, _currentElement);
49884911
id.staticElement = idElement;
49894912
id.staticType = type;
49904913
setIsDynamicInvoke(id, dynamicInvoke ?? type.isDynamic);
@@ -6508,17 +6431,19 @@ JS.LiteralString _propertyName(String name) => js.string(name, "'");
65086431
class TemporaryVariableElement extends LocalVariableElementImpl {
65096432
final JS.Expression jsVariable;
65106433

6511-
TemporaryVariableElement.forNode(Identifier name, this.jsVariable)
6512-
: super.forNode(name);
6434+
TemporaryVariableElement.forNode(
6435+
Identifier name, this.jsVariable, Element enclosingElement)
6436+
: super.forNode(name) {
6437+
this.enclosingElement = enclosingElement is ElementHandle
6438+
? enclosingElement.actualElement
6439+
: enclosingElement;
6440+
}
65136441

65146442
int get hashCode => identityHashCode(this);
65156443

65166444
bool operator ==(Object other) => identical(this, other);
65176445
}
65186446

6519-
LibraryElement _getLibrary(AnalysisContext c, String uri) =>
6520-
c.computeLibraryElement(c.sourceFactory.forUri(uri));
6521-
65226447
/// Returns `true` if [target] is a prefix for a deferred library and [name]
65236448
/// is "loadLibrary".
65246449
///

0 commit comments

Comments
 (0)