mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
Revert "[dartdevc] cleaning up unused web files"
This reverts commit e866f043cf
.
Reason for revert: Breaks google3.
Original change's description:
> [dartdevc] cleaning up unused web files
>
> Dependent on these google3 changes: https://critique.corp.google.com/#review/272749649
>
> Change-Id: I9e89142cd5b2a619acfc35badb9cf3c549b3be9c
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119587
> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
> Commit-Queue: Mark Zhou <markzipan@google.com>
TBR=scheglov@google.com,vsm@google.com,markzipan@google.com
Change-Id: I1db094d94d699d4d18c4091f57c7cb775eb95dd5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/120040
Reviewed-by: David Morgan <davidmorgan@google.com>
Commit-Queue: David Morgan <davidmorgan@google.com>
This commit is contained in:
parent
ad78373d6c
commit
d6c6d12ebf
|
@ -82,13 +82,6 @@ main() { foo(() {}); }
|
||||||
|
|
||||||
### Dart VM
|
### Dart VM
|
||||||
|
|
||||||
### Dart for the Web
|
|
||||||
|
|
||||||
#### Dart Dev Compiler (DDC)
|
|
||||||
|
|
||||||
* Kernel DDC will no longer accept non-dill files as summary inputs.
|
|
||||||
* Removed support for the deprecated web extension.
|
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
#### Pub
|
#### Pub
|
||||||
|
|
72
pkg/dev_compiler/CHANGELOG.md
Normal file
72
pkg/dev_compiler/CHANGELOG.md
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# dev_compiler changelog
|
||||||
|
|
||||||
|
## next release
|
||||||
|
- add support for AMD modules and make it the default.
|
||||||
|
- precompile the SDK in AMD, CommonJS, and ES6 flavors.
|
||||||
|
- legacy module format is deprecated.
|
||||||
|
- remove --package-paths option
|
||||||
|
|
||||||
|
## 0.1.24
|
||||||
|
- workaround breaking change on requestAnimationFrame
|
||||||
|
|
||||||
|
## 0.1.23
|
||||||
|
- updates for the latest analyzer
|
||||||
|
- removal of deprecated functionality (server mode) in prep for refactoring
|
||||||
|
|
||||||
|
## 0.1.22
|
||||||
|
- fixes to support the latest analyzer
|
||||||
|
- improvements in compile speed
|
||||||
|
- bug fixes on function / closure handling
|
||||||
|
|
||||||
|
## 0.1.21
|
||||||
|
- bug fix for dart:js constructor invocation
|
||||||
|
|
||||||
|
## 0.1.20
|
||||||
|
- support new StackTrace.current method
|
||||||
|
|
||||||
|
## 0.1.19
|
||||||
|
- support for dom libraries (dart:html, etc)
|
||||||
|
|
||||||
|
## 0.1.18
|
||||||
|
- dart:typed_data support
|
||||||
|
- preliminary TS / Closure output support
|
||||||
|
- various runtime typing fixes
|
||||||
|
|
||||||
|
## 0.1.17
|
||||||
|
- preliminary node module support
|
||||||
|
- support for compiling / serving multiple html files
|
||||||
|
|
||||||
|
## 0.1.16
|
||||||
|
- rolled analyzer to 0.27.2-alpha.1
|
||||||
|
- fixes for static fields
|
||||||
|
|
||||||
|
## 0.1.15
|
||||||
|
- codegen fixes for dart:convert (json decode) and dart:math (max, min)
|
||||||
|
|
||||||
|
## 0.1.14
|
||||||
|
- updates to unpin analyzer and move forward to ^0.27.1+2
|
||||||
|
|
||||||
|
## 0.1.13
|
||||||
|
- various fixes in js codegen
|
||||||
|
- pinned to analyzer 0.26.2+1 to avoid breaking upstream changes
|
||||||
|
|
||||||
|
## 0.1.12
|
||||||
|
- fixes for babel
|
||||||
|
- fixes toward new js interop
|
||||||
|
|
||||||
|
## 0.1.11
|
||||||
|
- moved js runtime files to lib/runtime/dart (`dart_runtime.js` -> `dart/_runtime.js`)
|
||||||
|
- bug fix to source maps
|
||||||
|
- initial support for f-bound quantification patterns
|
||||||
|
|
||||||
|
## 0.1.10
|
||||||
|
- added an `--html-report` option to create a file summarizing compilation
|
||||||
|
issues
|
||||||
|
- added a `-f` alias to the `--force-compile` command line option
|
||||||
|
- removed many info level messages that were informational to the DDC team
|
||||||
|
|
||||||
|
## 0.1.9
|
||||||
|
|
||||||
|
## 0.1.8
|
||||||
|
- added a `--version` command-line option
|
||||||
|
- added a new entry-point - `dev_compiler` - that aliases to `dartdevc`
|
917
pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
Normal file
917
pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
Normal file
|
@ -0,0 +1,917 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import 'dart:collection';
|
||||||
|
import 'dart:core' hide MapEntry;
|
||||||
|
|
||||||
|
import 'package:analyzer/dart/element/element.dart' as a;
|
||||||
|
import 'package:analyzer/dart/element/type.dart' as a;
|
||||||
|
import 'package:analyzer/file_system/physical_file_system.dart' as a;
|
||||||
|
import 'package:analyzer/src/context/context.dart' as a;
|
||||||
|
import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart'
|
||||||
|
as a;
|
||||||
|
import 'package:analyzer/src/dart/element/element.dart' as a;
|
||||||
|
import 'package:analyzer/src/dart/element/member.dart' as a;
|
||||||
|
import 'package:analyzer/src/dart/element/type.dart' as a;
|
||||||
|
import 'package:analyzer/src/generated/constant.dart' as a;
|
||||||
|
import 'package:analyzer/src/generated/engine.dart' as a;
|
||||||
|
import 'package:analyzer/src/generated/resolver.dart' as a
|
||||||
|
show NamespaceBuilder, TypeProvider;
|
||||||
|
import 'package:analyzer/src/generated/source.dart' as a;
|
||||||
|
import 'package:analyzer/src/generated/type_system.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary/idl.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary/package_bundle_reader.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary/summary_sdk.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary2/linked_bundle_context.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary2/linked_element_factory.dart' as a;
|
||||||
|
import 'package:analyzer/src/summary2/reference.dart' as a;
|
||||||
|
import 'package:front_end/src/api_unstable/ddc.dart'
|
||||||
|
show RedirectingFactoryBody;
|
||||||
|
import 'package:kernel/kernel.dart';
|
||||||
|
import 'package:kernel/type_algebra.dart';
|
||||||
|
|
||||||
|
import '../analyzer/type_utilities.dart' hide freeTypeParameters;
|
||||||
|
import 'type_table.dart';
|
||||||
|
|
||||||
|
/// Converts an Analyzer summary file to a Kernel [Component].
|
||||||
|
///
|
||||||
|
/// The first step is to use Analyzer's [a.StoreBasedSummaryResynthesizer] to
|
||||||
|
/// deserialize the summary file into an [a.Element] model (that way we don't
|
||||||
|
/// depend directly on the file format). Once we have elements, we visit them
|
||||||
|
/// and construct the corresponding Kernel [Node]s.
|
||||||
|
///
|
||||||
|
/// The main entry points are [convertSdk] and [convertSummaries], which
|
||||||
|
/// convert the SDK and input summaries, respectively.
|
||||||
|
///
|
||||||
|
/// Because we only need to convert summaries, we do not need to handle method
|
||||||
|
/// bodies. This lets us avoid the complexity of converting Analyzer AST nodes
|
||||||
|
/// (e.g. expressions, statements).
|
||||||
|
///
|
||||||
|
/// For constants we use Analyzer's constant evaluator compute the value from
|
||||||
|
/// the data in the summary, and then create the appropriate Kernel node to
|
||||||
|
/// reconstruct the constant (e.g. ListLiteral, ConstructorInvocation, etc).
|
||||||
|
/// See [_visitConstant] for more information.
|
||||||
|
///
|
||||||
|
/// When something refers to an element, we normally create the [Reference] but
|
||||||
|
/// leave its corresponding [NamedNode] empty until that element is visited and
|
||||||
|
/// creates the Kernel node. This takes care of cycles, and avoids recursing too
|
||||||
|
/// deeply as we convert elements.
|
||||||
|
///
|
||||||
|
/// Sometimes we need to convert an element eagerly (e.g. if we need to call
|
||||||
|
/// members on an [InterfaceType] or [Supertype], we need to create its [Class]
|
||||||
|
/// node). In that case we handle cycles in the visit method (e.g.
|
||||||
|
/// [visitClassElement]) by creating the node and linking it to its reference
|
||||||
|
/// before visiting anything else that might recurse.
|
||||||
|
///
|
||||||
|
/// Special care must be taken to make sure we link up all [Reference]s with
|
||||||
|
/// their corresponding [NamedNode]. If we don't do this [verifyReferences]
|
||||||
|
/// will throw an error. The fix is to figure out why we didn't visit the
|
||||||
|
/// element for that reference (often this is due to Analyzer's synthetic
|
||||||
|
/// fields/accessor elements; care must be taken to always reference the real
|
||||||
|
/// element).
|
||||||
|
///
|
||||||
|
/// Because we're using Analyzer's summary resynthesizer, conversion is all or
|
||||||
|
/// nothing: all summaries must be in Analyzer format, including the SDK.
|
||||||
|
/// Now that we have this implementation, it may be possible to port code from
|
||||||
|
/// Analyzer and modify it to resynthesize directly into Kernel trees, if we
|
||||||
|
/// ever need to support a mix of Kernel and Analyzer summary files.
|
||||||
|
class AnalyzerToKernel {
|
||||||
|
final a.LinkedElementFactory _resynth;
|
||||||
|
final a.SummaryDataStore _summaryData;
|
||||||
|
final a.TypeProvider types;
|
||||||
|
final a.Dart2TypeSystem rules;
|
||||||
|
|
||||||
|
final _references = HashMap<a.Element, Reference>();
|
||||||
|
final _typeParams = HashMap<a.TypeParameterElement, TypeParameter>();
|
||||||
|
final _namespaceBuilder = a.NamespaceBuilder();
|
||||||
|
|
||||||
|
AnalyzerToKernel._(this._resynth, this._summaryData)
|
||||||
|
: types = _resynth.analysisContext.typeProvider,
|
||||||
|
rules = _resynth.analysisContext.typeSystem as a.Dart2TypeSystem;
|
||||||
|
|
||||||
|
/// Create an Analyzer summary to Kernel tree converter, using the provided
|
||||||
|
/// [analyzerSdkSummary] and [summaryPaths].
|
||||||
|
///
|
||||||
|
/// Once the converter is created, [convertSdk] should be called to convert
|
||||||
|
/// & return the SDK, followed by [convertSummaries] to convert & return the
|
||||||
|
/// converted summaries.
|
||||||
|
factory AnalyzerToKernel(
|
||||||
|
String analyzerSdkSummary, List<String> summaryPaths) {
|
||||||
|
var summaryData = a.SummaryDataStore(summaryPaths,
|
||||||
|
resourceProvider: a.PhysicalResourceProvider.INSTANCE,
|
||||||
|
disallowOverlappingSummaries: false);
|
||||||
|
var resynthesizer =
|
||||||
|
_createSummaryResynthesizer(summaryData, analyzerSdkSummary);
|
||||||
|
return AnalyzerToKernel._(resynthesizer, summaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the SDK summary to a Kernel component and returns it.
|
||||||
|
Component convertSdk() {
|
||||||
|
// _createContextForSummaries puts the SDK summary last in the summary data.
|
||||||
|
var sdkBundle = _summaryData.bundles.last;
|
||||||
|
assert(sdkBundle.linkedLibraryUris.every((u) => u.startsWith('dart:')));
|
||||||
|
var result = _toComponent(sdkBundle);
|
||||||
|
verifyReferences();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the input summaries to Kernel components and return them.
|
||||||
|
///
|
||||||
|
/// [convertSdk] must be called before this.
|
||||||
|
List<Component> convertSummaries() {
|
||||||
|
// Take all summaries except the SDK one, which is placed last in the list
|
||||||
|
// by _createContextForSummaries.
|
||||||
|
var bundles = _summaryData.bundles.take(_summaryData.bundles.length - 1);
|
||||||
|
var result = bundles.map(_toComponent).toList();
|
||||||
|
verifyReferences(); // assumption: convertSdk() is called first
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifyReferences() {
|
||||||
|
_references.forEach((element, reference) {
|
||||||
|
// Ensure each reference has a corresponding node.
|
||||||
|
//
|
||||||
|
// If it's missing a node, CFE will fail and it is difficult to debug at
|
||||||
|
// that point because the name and element cannot be accessed.
|
||||||
|
//
|
||||||
|
// Typically this error means:
|
||||||
|
// - we didn't visit an element.
|
||||||
|
// - we didn't set the `reference: _reference(e)` for the Kernel node.
|
||||||
|
// - we referenced a synthetic element by mistake, such as referencing the
|
||||||
|
// synthetic getter/setter, when we should've used the field.
|
||||||
|
if (reference.node == null) {
|
||||||
|
throw StateError('missing node for reference, element was: $element' +
|
||||||
|
(element.isSynthetic ? ' (synthetic)' : ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Component _toComponent(a.PackageBundle bundle) {
|
||||||
|
var libraries = <Library>[];
|
||||||
|
var uriToSource = <Uri, Source>{};
|
||||||
|
|
||||||
|
void addCompilationUnit(a.CompilationUnitElement unit) {
|
||||||
|
uriToSource[unit.source.uri] = Source(
|
||||||
|
unit.lineInfo.lineStarts,
|
||||||
|
[],
|
||||||
|
unit.uri != null ? Uri.base.resolve(unit.uri) : unit.source.uri,
|
||||||
|
unit.source.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var uri in bundle.unlinkedUnitUris) {
|
||||||
|
if (_summaryData.isPartUnit(uri)) {
|
||||||
|
// Library parts are handled by their corresponding library.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = _resynth.libraryOfUri(uri);
|
||||||
|
libraries.add(visitLibraryElement(element));
|
||||||
|
addCompilationUnit(element.definingCompilationUnit);
|
||||||
|
element.parts.forEach(addCompilationUnit);
|
||||||
|
}
|
||||||
|
return Component(libraries: libraries, uriToSource: uriToSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class visitClassElement(a.ClassElement e, [Library library]) {
|
||||||
|
var ref = _reference(e);
|
||||||
|
if (ref.node != null) return ref.asClass;
|
||||||
|
|
||||||
|
// Construct the Class first and link the reference. This ensures the
|
||||||
|
// (not yet finished) Class node will be returned on the line above, if we
|
||||||
|
// happen to re-enter this visit method.
|
||||||
|
var class_ = Class(
|
||||||
|
name: e.name,
|
||||||
|
isAbstract: e.isAbstract,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: ref);
|
||||||
|
|
||||||
|
// Classes can be visited before their library (e.g. because they're a
|
||||||
|
// supertype of another class), so make sure to visit the library now.
|
||||||
|
library ??= visitLibraryElement(e.library);
|
||||||
|
library.addClass(class_);
|
||||||
|
|
||||||
|
class_.isMixinDeclaration = e.isMixin;
|
||||||
|
class_.typeParameters
|
||||||
|
.addAll(e.typeParameters.map(visitTypeParameterElement));
|
||||||
|
|
||||||
|
setParents(class_.typeParameters, class_);
|
||||||
|
class_.implementedTypes.addAll(e.interfaces.map(_typeToSupertype));
|
||||||
|
|
||||||
|
var fields = class_.fields;
|
||||||
|
var constructors = class_.constructors;
|
||||||
|
var procedures = class_.procedures;
|
||||||
|
|
||||||
|
fields.addAll(e.fields.where((f) => !f.isSynthetic).map(visitFieldElement));
|
||||||
|
|
||||||
|
var redirectingFactories = <Procedure>[];
|
||||||
|
for (var ctor in e.constructors) {
|
||||||
|
if (ctor.isFactory) {
|
||||||
|
var factory_ = _visitFactory(ctor);
|
||||||
|
procedures.add(factory_);
|
||||||
|
if (ctor.redirectedConstructor != null) {
|
||||||
|
redirectingFactories.add(factory_);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constructors.add(visitConstructorElement(ctor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (redirectingFactories.isNotEmpty) {
|
||||||
|
fields.add(_createRedirectingFactoryField(redirectingFactories, e));
|
||||||
|
}
|
||||||
|
procedures.addAll(e.methods.map(visitMethodElement));
|
||||||
|
procedures.addAll(e.accessors
|
||||||
|
.where((a) => !a.isSynthetic)
|
||||||
|
.map(visitPropertyAccessorElement));
|
||||||
|
|
||||||
|
setParents(fields, class_);
|
||||||
|
setParents(constructors, class_);
|
||||||
|
setParents(procedures, class_);
|
||||||
|
|
||||||
|
if (e.isMixinApplication) {
|
||||||
|
class_.mixedInType = _typeToSupertype(e.mixins.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
var supertype = _typeToSupertype(e.supertype);
|
||||||
|
class_.supertype = _unrollMixinClasses(e, supertype, library);
|
||||||
|
_visitAnnotations(e.metadata, class_.addAnnotation);
|
||||||
|
|
||||||
|
// TODO(jmesserly): do we need covariance check stubs? We may be okay as
|
||||||
|
// since we're only handling dependencies here.
|
||||||
|
//
|
||||||
|
// But this may lead to redundant stubs (if CFE doesn't see one on a
|
||||||
|
// superclass) and/or break some assumptions in CFE.
|
||||||
|
return class_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Supertype _unrollMixinClasses(
|
||||||
|
a.ClassElement e, Supertype supertype, Library library) {
|
||||||
|
// TODO(jmesserly): is this enough for mixin desugaring? It only does
|
||||||
|
// enough to create the intermediate classes.
|
||||||
|
|
||||||
|
// Documentation below assumes the given mixin application is in one of
|
||||||
|
// these forms:
|
||||||
|
//
|
||||||
|
// class C extends S with M1, M2, M3;
|
||||||
|
// class Named = S with M1, M2, M3;
|
||||||
|
//
|
||||||
|
// When we refer to the subclass, we mean `C` or `Named`.
|
||||||
|
|
||||||
|
/// The number of mixin classes to unroll.
|
||||||
|
///
|
||||||
|
/// Named mixin applications have one less class. This can be illustrated
|
||||||
|
/// here:
|
||||||
|
///
|
||||||
|
/// class C extends S with M1, M2, M3 {}
|
||||||
|
/// class Named = S with M1, M2, M3;
|
||||||
|
///
|
||||||
|
/// For `C` we unroll 3 classes: _C&S&M1, _C&S&M1&M2, _C&S&M1&M2&M3.
|
||||||
|
/// For `Named` we unroll 2 classes: _Named&S&M1, _Named&S&M1&M2.
|
||||||
|
///
|
||||||
|
/// The classes themselves will be generated as:
|
||||||
|
///
|
||||||
|
/// class C extends _C&S&M1&M2&M3 {}
|
||||||
|
/// class Named = _Named&S&M1&M2 with M3;
|
||||||
|
///
|
||||||
|
var unrollLength = e.mixins.length;
|
||||||
|
if (e.isMixinApplication) unrollLength--;
|
||||||
|
if (unrollLength <= 0) return supertype;
|
||||||
|
|
||||||
|
/// The mixin application's synthetic name.
|
||||||
|
///
|
||||||
|
/// The full name of the mixin application is obtained by prepending the
|
||||||
|
/// name of the subclass (`C` or `Named` in the above examples) to the
|
||||||
|
/// running name. For the example `C`, that leads to these names:
|
||||||
|
///
|
||||||
|
/// 1. `_C&S&M1`
|
||||||
|
/// 2. `_C&S&M1&M2`
|
||||||
|
/// 3. `_C&S&M1&M2&M3`.
|
||||||
|
var runningName = '_${e.name}&${e.supertype.name}';
|
||||||
|
|
||||||
|
/// The type variables used in the current supertype and mixin, or null
|
||||||
|
/// if this class doesn't have any type parameters.
|
||||||
|
var usedTypeVars = e.typeParameters.isNotEmpty
|
||||||
|
? freeTypeParameters(supertype.asInterfaceType)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
for (int i = 0; i < unrollLength; i++) {
|
||||||
|
var mixin = e.mixins[i];
|
||||||
|
runningName += "&${mixin.name}";
|
||||||
|
|
||||||
|
var mixedInType = _typeToSupertype(mixin);
|
||||||
|
List<TypeParameter> typeParameters;
|
||||||
|
if (usedTypeVars != null) {
|
||||||
|
// Any type params used by superclasses will continue to be used, plus
|
||||||
|
// anything additional that this mixin uses.
|
||||||
|
usedTypeVars.addAll(freeTypeParameters(mixedInType.asInterfaceType));
|
||||||
|
if (usedTypeVars.isNotEmpty) {
|
||||||
|
// Make fresh type parameters for this class, and then substitute them
|
||||||
|
// into supertype and mixin type arguments (if any).
|
||||||
|
var fresh = getFreshTypeParameters(usedTypeVars.toList());
|
||||||
|
typeParameters = fresh.freshTypeParameters;
|
||||||
|
supertype = fresh.substituteSuper(supertype);
|
||||||
|
mixedInType = fresh.substituteSuper(mixedInType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = Class(
|
||||||
|
name: runningName,
|
||||||
|
isAbstract: true,
|
||||||
|
mixedInType: mixedInType,
|
||||||
|
supertype: supertype,
|
||||||
|
typeParameters: typeParameters,
|
||||||
|
fileUri: e.source.uri);
|
||||||
|
|
||||||
|
library.addClass(c);
|
||||||
|
|
||||||
|
// Compute the superclass to use for the next iteration of this loop.
|
||||||
|
//
|
||||||
|
// Any type arguments are in terms of the original class type parameters.
|
||||||
|
// This allows us to perform consistent substitutions and have the correct
|
||||||
|
// type arguments for the final supertype (that we return).
|
||||||
|
supertype = Supertype(
|
||||||
|
c,
|
||||||
|
typeParameters != null
|
||||||
|
? List.of(usedTypeVars.map((t) => TypeParameterType(t)))
|
||||||
|
: []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return supertype;
|
||||||
|
}
|
||||||
|
|
||||||
|
Constructor visitConstructorElement(a.ConstructorElement e) {
|
||||||
|
assert(!e.isFactory);
|
||||||
|
var ref = _reference(e);
|
||||||
|
if (ref.node != null) return ref.asConstructor;
|
||||||
|
// By convention, instance constructors return `void` in Kernel.
|
||||||
|
var function = _createFunction(e)..returnType = const VoidType();
|
||||||
|
var result = Constructor(function,
|
||||||
|
name: _getName(e),
|
||||||
|
isConst: e.isConst,
|
||||||
|
isExternal: e.isExternal,
|
||||||
|
isSynthetic: e.isSynthetic,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: ref);
|
||||||
|
if (!result.isSynthetic) {
|
||||||
|
// TODO(jmesserly): CFE does not respect the synthetic bit on constructors
|
||||||
|
// so we set a bogus offset. This causes CFE to treat it as not synthetic.
|
||||||
|
//
|
||||||
|
// (The bug is in DillMemberBuilder.isSynthetic. Synthetic constructors
|
||||||
|
// have different semantics/optimizations in some cases, so it is
|
||||||
|
// important that the constructor is correctly marked.)
|
||||||
|
result.fileOffset = 1;
|
||||||
|
}
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Procedure _visitFactory(a.ConstructorElement e) {
|
||||||
|
var ref = _reference(e);
|
||||||
|
if (ref.node != null) return ref.asProcedure;
|
||||||
|
|
||||||
|
var result = Procedure.byReference(_getName(e), ProcedureKind.Factory, null,
|
||||||
|
isExternal: e.isExternal,
|
||||||
|
isConst: e.isConst,
|
||||||
|
isStatic: true,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: ref);
|
||||||
|
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
|
||||||
|
// Since the factory is static, we need to create fresh type parameters that
|
||||||
|
// match the ones in the enclosing class.
|
||||||
|
FreshTypeParameters fresh;
|
||||||
|
DartType Function(a.DartType) visitType;
|
||||||
|
|
||||||
|
if (e.enclosingElement.typeParameters.isNotEmpty) {
|
||||||
|
fresh = getFreshTypeParameters(
|
||||||
|
visitClassElement(e.enclosingElement).typeParameters);
|
||||||
|
visitType = (t) => fresh.substitute(_visitDartType(t, ensureNode: true));
|
||||||
|
} else {
|
||||||
|
visitType = _visitDartType;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.function = _createFunction(e, fresh?.freshTypeParameters, visitType);
|
||||||
|
result.function.parent = result;
|
||||||
|
|
||||||
|
var redirect = e.redirectedConstructor;
|
||||||
|
if (redirect == null) return result;
|
||||||
|
|
||||||
|
// Get the raw constructor element before the type is applied.
|
||||||
|
var rawRedirect =
|
||||||
|
redirect is a.ConstructorMember ? redirect.baseElement : redirect;
|
||||||
|
|
||||||
|
// TODO(jmesserly): conceptually we only need a reference here, but
|
||||||
|
// RedirectingFactoryBody requires the complete node.
|
||||||
|
var ctor = rawRedirect.isFactory
|
||||||
|
? _visitFactory(rawRedirect)
|
||||||
|
: visitConstructorElement(rawRedirect);
|
||||||
|
|
||||||
|
var redirectedType = redirect.type.returnType as a.InterfaceType;
|
||||||
|
var typeArgs = redirectedType.typeArguments.map(visitType).toList();
|
||||||
|
result.function.body = RedirectingFactoryBody(ctor, typeArgs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field _createRedirectingFactoryField(
|
||||||
|
List<Procedure> factories, a.ClassElement c) {
|
||||||
|
return Field(_getName(c, "_redirecting#"),
|
||||||
|
isStatic: true,
|
||||||
|
initializer: ListLiteral(List.of(factories.map((f) => StaticGet(f)))),
|
||||||
|
fileUri: c.source.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
LibraryDependency visitExportElement(a.ExportElement e) =>
|
||||||
|
LibraryDependency.byReference(
|
||||||
|
LibraryDependency.ExportFlag,
|
||||||
|
const [],
|
||||||
|
_reference(e.exportedLibrary),
|
||||||
|
null,
|
||||||
|
e.combinators.map(_visitCombinator).toList());
|
||||||
|
|
||||||
|
Field visitFieldElement(a.FieldElement e) {
|
||||||
|
var result = Field(_getName(e),
|
||||||
|
type: _visitDartType(e.type),
|
||||||
|
initializer: null,
|
||||||
|
isFinal: e.isFinal,
|
||||||
|
isConst: e.isConst,
|
||||||
|
isStatic: e.isStatic,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: _reference(e));
|
||||||
|
if (!e.isFinal && !e.isConst) {
|
||||||
|
var class_ = e.enclosingElement as a.ClassElement;
|
||||||
|
if (class_.typeParameters.isNotEmpty) {
|
||||||
|
result.isGenericCovariantImpl = _isGenericCovariant(class_, e.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Procedure visitFunctionElement(a.FunctionElement e) {
|
||||||
|
var result = Procedure.byReference(
|
||||||
|
_getName(e), ProcedureKind.Method, _createFunction(e),
|
||||||
|
isExternal: e.isExternal,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
isStatic: true,
|
||||||
|
reference: _reference(e));
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Typedef visitFunctionTypeAliasElement(a.FunctionTypeAliasElement e,
|
||||||
|
[Library library]) {
|
||||||
|
var ref = _reference(e);
|
||||||
|
if (ref.node != null) return ref.asTypedef;
|
||||||
|
|
||||||
|
var t = Typedef(e.name, null, reference: ref, fileUri: e.source.uri);
|
||||||
|
library ??= visitLibraryElement(e.library);
|
||||||
|
library.addTypedef(t);
|
||||||
|
|
||||||
|
a.FunctionType type;
|
||||||
|
var typeParams = e.typeParameters;
|
||||||
|
if (e is a.GenericTypeAliasElement) {
|
||||||
|
type = e.function.type;
|
||||||
|
} else {
|
||||||
|
type = e.type;
|
||||||
|
if (typeParams.isNotEmpty) {
|
||||||
|
// Skip past the type formals, we'll add them back below, so these
|
||||||
|
// type parameter names will end up in scope in the generated JS.
|
||||||
|
type = type.instantiate(
|
||||||
|
typeParams.map((f) => getLegacyTypeParameterType(f)).toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.typeParameters.addAll(typeParams.map(visitTypeParameterElement));
|
||||||
|
setParents(t.typeParameters, t);
|
||||||
|
t.type = _visitDartType(type, originTypedef: t.thisType);
|
||||||
|
_visitAnnotations(e.metadata, t.addAnnotation);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibraryDependency visitImportElement(a.ImportElement e) =>
|
||||||
|
LibraryDependency.byReference(0, const [], _reference(e.importedLibrary),
|
||||||
|
null, e.combinators.map(_visitCombinator).toList());
|
||||||
|
|
||||||
|
Library visitLibraryElement(a.LibraryElement e) {
|
||||||
|
var ref = _reference(e);
|
||||||
|
if (ref.node != null) return ref.asLibrary;
|
||||||
|
|
||||||
|
var library = Library(e.source.uri,
|
||||||
|
name: e.name,
|
||||||
|
fileUri: e.definingCompilationUnit.source.uri,
|
||||||
|
reference: ref);
|
||||||
|
library.fileOffset = 0;
|
||||||
|
|
||||||
|
_visitAnnotations(e.metadata, library.addAnnotation);
|
||||||
|
e.imports.map(visitImportElement).forEach(library.addDependency);
|
||||||
|
e.exports.map(visitExportElement).forEach(library.addDependency);
|
||||||
|
e.parts.map((p) => LibraryPart(const [], p.uri)).forEach(library.addPart);
|
||||||
|
|
||||||
|
_visitUnit(a.CompilationUnitElement u) {
|
||||||
|
for (var t in u.types) {
|
||||||
|
visitClassElement(t, library);
|
||||||
|
}
|
||||||
|
for (var t in u.mixins) {
|
||||||
|
visitClassElement(t, library);
|
||||||
|
}
|
||||||
|
for (var t in u.functionTypeAliases) {
|
||||||
|
visitFunctionTypeAliasElement(t, library);
|
||||||
|
}
|
||||||
|
u.functions.map(visitFunctionElement).forEach(library.addMember);
|
||||||
|
u.accessors
|
||||||
|
.where((a) => !a.isSynthetic)
|
||||||
|
.map(visitPropertyAccessorElement)
|
||||||
|
.forEach(library.addMember);
|
||||||
|
u.topLevelVariables
|
||||||
|
.map(visitTopLevelVariableElement)
|
||||||
|
.forEach(library.addMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
_visitUnit(e.definingCompilationUnit);
|
||||||
|
e.parts.forEach(_visitUnit);
|
||||||
|
|
||||||
|
var libraryImpl = e as a.LibraryElementImpl;
|
||||||
|
libraryImpl.publicNamespace ??=
|
||||||
|
_namespaceBuilder.createPublicNamespaceForLibrary(e);
|
||||||
|
libraryImpl.exportNamespace ??=
|
||||||
|
_namespaceBuilder.createExportNamespaceForLibrary(e);
|
||||||
|
var publicNames = libraryImpl.publicNamespace.definedNames;
|
||||||
|
var exportNames = libraryImpl.exportNamespace.definedNames;
|
||||||
|
exportNames.forEach((name, value) {
|
||||||
|
if (!publicNames.containsKey(name)) {
|
||||||
|
value = value is a.PropertyAccessorElement && value.isSynthetic
|
||||||
|
? value.variable
|
||||||
|
: value;
|
||||||
|
library.additionalExports.add(_reference(value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return library;
|
||||||
|
}
|
||||||
|
|
||||||
|
Procedure visitMethodElement(a.MethodElement e) {
|
||||||
|
var result = Procedure.byReference(
|
||||||
|
_getName(e),
|
||||||
|
e.isOperator ? ProcedureKind.Operator : ProcedureKind.Method,
|
||||||
|
_createFunction(e),
|
||||||
|
isAbstract: e.isAbstract,
|
||||||
|
isStatic: e.isStatic,
|
||||||
|
isExternal: e.isExternal,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: _reference(e));
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Procedure visitPropertyAccessorElement(a.PropertyAccessorElement e) {
|
||||||
|
var result = Procedure.byReference(
|
||||||
|
_getName(e, e.variable.name),
|
||||||
|
e.isGetter ? ProcedureKind.Getter : ProcedureKind.Setter,
|
||||||
|
_createFunction(e),
|
||||||
|
isAbstract: e.isAbstract,
|
||||||
|
isStatic: e.isStatic,
|
||||||
|
isExternal: e.isExternal,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: _reference(e));
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field visitTopLevelVariableElement(a.TopLevelVariableElement e) {
|
||||||
|
var result = Field(_getName(e),
|
||||||
|
type: _visitDartType(e.type),
|
||||||
|
initializer: null,
|
||||||
|
isFinal: e.isFinal,
|
||||||
|
isConst: e.isConst,
|
||||||
|
isStatic: e.isStatic,
|
||||||
|
fileUri: e.source.uri,
|
||||||
|
reference: _reference(e));
|
||||||
|
_visitAnnotations(e.metadata, result.addAnnotation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeParameter visitTypeParameterElement(a.TypeParameterElement e) {
|
||||||
|
var t = _typeParams[e];
|
||||||
|
if (t != null) return t;
|
||||||
|
_typeParams[e] = t = TypeParameter(e.name);
|
||||||
|
|
||||||
|
var hasBound = e.bound != null;
|
||||||
|
t.bound =
|
||||||
|
hasBound ? _visitDartType(e.bound) : _visitDartType(types.objectType);
|
||||||
|
t.defaultType = hasBound ? t.bound : const DynamicType();
|
||||||
|
|
||||||
|
var enclosingElement = e.enclosingElement;
|
||||||
|
if (hasBound && enclosingElement is a.ClassMemberElement) {
|
||||||
|
var class_ = enclosingElement.enclosingElement;
|
||||||
|
if (class_ is a.ClassElement && class_.typeParameters.isNotEmpty) {
|
||||||
|
t.isGenericCovariantImpl = _isGenericCovariant(class_, e.bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Name _getName(a.Element e, [String name]) {
|
||||||
|
name ??= e.name;
|
||||||
|
return Name.byReference(
|
||||||
|
name, name.startsWith('_') ? _reference(e.library) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an Analyzer [type] to a Kernel type.
|
||||||
|
///
|
||||||
|
/// If [ensureNode] is set, the reference to the [Class] or [Typedef] will
|
||||||
|
/// populated with the node (creating it if needed). Many members on
|
||||||
|
/// [InterfaceType] and [TypedefType] rely on having a node present, so this
|
||||||
|
/// enables the use of those members if they're needed by the converter.
|
||||||
|
DartType _visitDartType(a.DartType type,
|
||||||
|
{bool ensureNode = false, TypedefType originTypedef}) {
|
||||||
|
if (type.isVoid) {
|
||||||
|
return const VoidType();
|
||||||
|
} else if (type.isDynamic) {
|
||||||
|
return const DynamicType();
|
||||||
|
} else if (type.isBottom) {
|
||||||
|
return const BottomType();
|
||||||
|
} else if (type is a.TypeParameterType) {
|
||||||
|
return TypeParameterType(visitTypeParameterElement(type.element));
|
||||||
|
}
|
||||||
|
|
||||||
|
visit(a.DartType t) => _visitDartType(t, ensureNode: ensureNode);
|
||||||
|
|
||||||
|
if (type is a.InterfaceType) {
|
||||||
|
var ref = ensureNode
|
||||||
|
? visitClassElement(type.element).reference
|
||||||
|
: _reference(type.element);
|
||||||
|
var typeArgs = type.typeArguments;
|
||||||
|
var newTypeArgs = typeArgs.isNotEmpty
|
||||||
|
? typeArgs.map(visit).toList()
|
||||||
|
: const <DartType>[];
|
||||||
|
return InterfaceType.byReference(ref, newTypeArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
var f = type as a.FunctionType;
|
||||||
|
if (f.name != null && f.name != '') {
|
||||||
|
var ref = ensureNode
|
||||||
|
? visitFunctionTypeAliasElement(
|
||||||
|
f.element as a.FunctionTypeAliasElement)
|
||||||
|
.reference
|
||||||
|
: _reference(f.element);
|
||||||
|
return TypedefType.byReference(ref, f.typeArguments.map(visit).toList());
|
||||||
|
}
|
||||||
|
var params = f.parameters;
|
||||||
|
var positional = f.normalParameterTypes.map(visit).toList();
|
||||||
|
positional.addAll(f.optionalParameterTypes.map(visit));
|
||||||
|
|
||||||
|
var named = <NamedType>[];
|
||||||
|
f.namedParameterTypes.forEach((name, type) {
|
||||||
|
named.add(NamedType(name, visit(type)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return FunctionType(positional, visit(f.returnType),
|
||||||
|
typeParameters: f.typeFormals.map(visitTypeParameterElement).toList(),
|
||||||
|
namedParameters: named,
|
||||||
|
requiredParameterCount: params.where((p) => !p.isOptional).length,
|
||||||
|
typedefType: originTypedef);
|
||||||
|
}
|
||||||
|
|
||||||
|
Supertype _typeToSupertype(a.InterfaceType t) {
|
||||||
|
if (t == null) return null;
|
||||||
|
return Supertype(
|
||||||
|
visitClassElement(t.element),
|
||||||
|
t.typeArguments
|
||||||
|
.map((a) => _visitDartType(a, ensureNode: true))
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Combinator _visitCombinator(a.NamespaceCombinator combinator) {
|
||||||
|
bool isShow;
|
||||||
|
List<String> names;
|
||||||
|
if (combinator is a.ShowElementCombinator) {
|
||||||
|
isShow = true;
|
||||||
|
names = combinator.shownNames;
|
||||||
|
} else {
|
||||||
|
isShow = false;
|
||||||
|
names = (combinator as a.HideElementCombinator).hiddenNames;
|
||||||
|
}
|
||||||
|
return Combinator(isShow, names);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a function node for the executable element [e], optionally using
|
||||||
|
/// the supplied [typeParameters] and calling [visitType] so it can perform
|
||||||
|
/// any necessary substitutions.
|
||||||
|
FunctionNode _createFunction(a.ExecutableElement e,
|
||||||
|
[List<TypeParameter> typeParameters,
|
||||||
|
DartType Function(a.DartType) visitType]) {
|
||||||
|
visitType ??= _visitDartType;
|
||||||
|
|
||||||
|
var enclosingElement = e.enclosingElement;
|
||||||
|
var class_ = enclosingElement is a.ClassElement ? enclosingElement : null;
|
||||||
|
|
||||||
|
visitParameter(a.ParameterElement e) {
|
||||||
|
var result = VariableDeclaration(e.name,
|
||||||
|
type: visitType(e.type),
|
||||||
|
isFinal: e.isFinal,
|
||||||
|
isFieldFormal: e.isInitializingFormal,
|
||||||
|
isCovariant: e.isCovariant,
|
||||||
|
initializer:
|
||||||
|
e.isOptional ? _visitConstant(e.computeConstantValue()) : null);
|
||||||
|
if (class_ != null && class_.typeParameters.isNotEmpty) {
|
||||||
|
result.isGenericCovariantImpl = _isGenericCovariant(class_, e.type);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = e.parameters;
|
||||||
|
var asyncMarker = _getAsyncMarker(e);
|
||||||
|
return FunctionNode(null,
|
||||||
|
typeParameters: typeParameters ??
|
||||||
|
e.typeParameters.map(visitTypeParameterElement).toList(),
|
||||||
|
positionalParameters:
|
||||||
|
params.where((p) => !p.isNamed).map(visitParameter).toList(),
|
||||||
|
namedParameters:
|
||||||
|
params.where((p) => p.isNamed).map(visitParameter).toList(),
|
||||||
|
requiredParameterCount: params.where((p) => !p.isOptional).length,
|
||||||
|
returnType: visitType(e.returnType),
|
||||||
|
asyncMarker: asyncMarker,
|
||||||
|
dartAsyncMarker: asyncMarker);
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference _reference(a.Element e) {
|
||||||
|
if (e == null) throw ArgumentError('null element');
|
||||||
|
return _references.putIfAbsent(e, () => Reference());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isGenericCovariant(a.ClassElement c, a.DartType type) {
|
||||||
|
var classUpperBound =
|
||||||
|
rules.instantiateToBounds(getLegacyRawClassType(c)) as a.InterfaceType;
|
||||||
|
var typeUpperBound = type.substitute2(classUpperBound.typeArguments,
|
||||||
|
a.TypeParameterTypeImpl.getTypes(classUpperBound.typeParameters));
|
||||||
|
// Is it safe to assign the upper bound of the field/parameter to it?
|
||||||
|
// If not then we'll need a runtime check.
|
||||||
|
return !rules.isSubtypeOf(typeUpperBound, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transforms a metadata annotation from Analyzer to Kernel format.
|
||||||
|
///
|
||||||
|
/// If needed this uses Analyzer's constant evaluation to evaluate the AST,
|
||||||
|
/// and then converts the resulting constant value into a Kernel tree.
|
||||||
|
/// By first computing the expression's constant value, we avoid having to
|
||||||
|
/// convert a bunch of Analyzer ASTs nodes. Instead we can convert the more
|
||||||
|
/// limited set of constant values allowed in Dart (see [_visitConstant]).
|
||||||
|
void _visitAnnotations(List<a.ElementAnnotation> metadata,
|
||||||
|
void Function(Expression) addAnnotation) {
|
||||||
|
if (metadata.isEmpty) return;
|
||||||
|
|
||||||
|
for (a.ElementAnnotation annotation in metadata) {
|
||||||
|
var ast = (annotation as a.ElementAnnotationImpl).annotationAst;
|
||||||
|
var arguments = ast.arguments;
|
||||||
|
if (arguments == null) {
|
||||||
|
var e = ast.element;
|
||||||
|
e = e is a.PropertyAccessorElement && e.isSynthetic ? e.variable : e;
|
||||||
|
addAnnotation(StaticGet.byReference(_reference(e)));
|
||||||
|
} else {
|
||||||
|
// Use Analyzer's constant evaluation to produce the constant, then
|
||||||
|
// emit the resulting value. We do this to avoid handling all of the
|
||||||
|
// AST nodes that might be needed for constant evaluation. Instead we
|
||||||
|
// just serialize the resulting value to a Kernel expression that will
|
||||||
|
// reproduce it.
|
||||||
|
addAnnotation(_visitConstant(annotation.computeConstantValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an Analyzer constant value in [obj] to a Kernel expression
|
||||||
|
/// (usually a Literal or ConstructorInvocation) that will recreate that
|
||||||
|
/// constant value.
|
||||||
|
Expression _visitConstant(a.DartObject obj) {
|
||||||
|
if (obj == null || obj.isNull || !obj.hasKnownValue) return NullLiteral();
|
||||||
|
|
||||||
|
var type = obj.type;
|
||||||
|
if (identical(type, types.boolType)) {
|
||||||
|
var value = obj.toBoolValue();
|
||||||
|
return value != null ? BoolLiteral(value) : NullLiteral();
|
||||||
|
}
|
||||||
|
if (identical(type, types.intType)) {
|
||||||
|
return IntLiteral(obj.toIntValue());
|
||||||
|
}
|
||||||
|
if (identical(type, types.doubleType)) {
|
||||||
|
return DoubleLiteral(obj.toDoubleValue());
|
||||||
|
}
|
||||||
|
if (identical(type, types.stringType)) {
|
||||||
|
return StringLiteral(obj.toStringValue());
|
||||||
|
}
|
||||||
|
if (identical(type, types.symbolType)) {
|
||||||
|
return SymbolLiteral(obj.toSymbolValue());
|
||||||
|
}
|
||||||
|
if (identical(type, types.typeType)) {
|
||||||
|
return TypeLiteral(_visitDartType(obj.toTypeValue()));
|
||||||
|
}
|
||||||
|
if (type is a.InterfaceType) {
|
||||||
|
if (type.element == types.listElement) {
|
||||||
|
return ListLiteral(obj.toListValue().map(_visitConstant).toList(),
|
||||||
|
typeArgument: _visitDartType(type.typeArguments[0]), isConst: true);
|
||||||
|
}
|
||||||
|
if (type.element == types.mapElement) {
|
||||||
|
var entries = obj
|
||||||
|
.toMapValue()
|
||||||
|
.entries
|
||||||
|
.map(
|
||||||
|
(e) => MapEntry(_visitConstant(e.key), _visitConstant(e.value)))
|
||||||
|
.toList();
|
||||||
|
return MapLiteral(entries,
|
||||||
|
keyType: _visitDartType(type.typeArguments[0]),
|
||||||
|
valueType: _visitDartType(type.typeArguments[1]),
|
||||||
|
isConst: true);
|
||||||
|
}
|
||||||
|
if (obj is a.DartObjectImpl && obj.isUserDefinedObject) {
|
||||||
|
var classElem = type.element;
|
||||||
|
if (classElem.isEnum) {
|
||||||
|
// TODO(jmesserly): we should be able to use `getField('index')` but
|
||||||
|
// in some cases Analyzer uses the name of the static field that
|
||||||
|
// contains the enum, rather than the `index` field, due to a bug.
|
||||||
|
//
|
||||||
|
// So we just grab the one instance field, regardless of its name.
|
||||||
|
var index = obj.fields.values.single.toIntValue();
|
||||||
|
var field =
|
||||||
|
classElem.fields.where((f) => f.type == type).elementAt(index);
|
||||||
|
return StaticGet.byReference(_reference(field));
|
||||||
|
}
|
||||||
|
var invocation = obj.getInvocation();
|
||||||
|
var constructor = invocation.constructor;
|
||||||
|
// For a redirecting const factory, the constant constructor will be
|
||||||
|
// from the original one, but the `type` will match the redirected type.
|
||||||
|
//
|
||||||
|
// This leads to mismatch in how we call this constructor. So we need to
|
||||||
|
// find the redirected one.
|
||||||
|
for (a.ConstructorElement rc;
|
||||||
|
(rc = constructor.redirectedConstructor) != null;) {
|
||||||
|
constructor = rc;
|
||||||
|
}
|
||||||
|
constructor = constructor is a.ConstructorMember
|
||||||
|
? constructor.baseElement
|
||||||
|
: constructor;
|
||||||
|
return ConstructorInvocation.byReference(
|
||||||
|
_reference(constructor),
|
||||||
|
Arguments(
|
||||||
|
invocation.positionalArguments.map(_visitConstant).toList(),
|
||||||
|
named: invocation.namedArguments.entries
|
||||||
|
.map((e) => NamedExpression(e.key, _visitConstant(e.value)))
|
||||||
|
.toList(),
|
||||||
|
types: type.typeArguments.map(_visitDartType).toList()),
|
||||||
|
isConst: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj is a.DartObjectImpl && type is a.FunctionType) {
|
||||||
|
var e = obj.toFunctionValue();
|
||||||
|
e = e is a.PropertyAccessorElement && e.isSynthetic
|
||||||
|
? e.variable as a.ExecutableElement
|
||||||
|
: e;
|
||||||
|
// TODO(jmesserly): support generic tear-off implicit instantiation.
|
||||||
|
return StaticGet.byReference(_reference(e));
|
||||||
|
}
|
||||||
|
throw UnsupportedError('unknown constant type `$type`: $obj');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncMarker _getAsyncMarker(a.ExecutableElement e) {
|
||||||
|
return e.isGenerator
|
||||||
|
? (e.isAsynchronous ? AsyncMarker.AsyncStar : AsyncMarker.SyncStar)
|
||||||
|
: (e.isAsynchronous ? AsyncMarker.Async : AsyncMarker.Sync);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.LinkedElementFactory _createSummaryResynthesizer(
|
||||||
|
a.SummaryDataStore summaryData, String dartSdkPath) {
|
||||||
|
var context = _createContextForSummaries(summaryData, dartSdkPath);
|
||||||
|
|
||||||
|
var elementFactory = a.LinkedElementFactory(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
a.Reference.root(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (var bundle in summaryData.bundles) {
|
||||||
|
elementFactory.addBundle(
|
||||||
|
a.LinkedBundleContext(elementFactory, bundle.bundle2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a dummy Analyzer context so we can use summary resynthesizer.
|
||||||
|
///
|
||||||
|
/// This is similar to Analyzer's `LibraryContext._createResynthesizingContext`.
|
||||||
|
a.AnalysisContextImpl _createContextForSummaries(
|
||||||
|
a.SummaryDataStore summaryData, String dartSdkPath) {
|
||||||
|
var sdk = a.SummaryBasedDartSdk(dartSdkPath, true,
|
||||||
|
resourceProvider: a.PhysicalResourceProvider.INSTANCE);
|
||||||
|
var sdkSummaryBundle = sdk.getLinkedBundle();
|
||||||
|
if (sdkSummaryBundle != null) {
|
||||||
|
summaryData.addBundle(null, sdkSummaryBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jmesserly): use RestrictedAnalysisContext.
|
||||||
|
var context = a.AnalysisEngine.instance.createAnalysisContext()
|
||||||
|
as a.AnalysisContextImpl;
|
||||||
|
context.sourceFactory = a.SourceFactory(
|
||||||
|
[a.DartUriResolver(sdk), a.InSummaryUriResolver(null, summaryData)]);
|
||||||
|
// TODO(jmesserly): do we need to set analysisOptions or declaredVariables?
|
||||||
|
return context;
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import '../js_ast/js_ast.dart' as js_ast;
|
||||||
import '../js_ast/js_ast.dart' show js;
|
import '../js_ast/js_ast.dart' show js;
|
||||||
import '../js_ast/source_map_printer.dart' show SourceMapPrintingContext;
|
import '../js_ast/source_map_printer.dart' show SourceMapPrintingContext;
|
||||||
|
|
||||||
|
import 'analyzer_to_kernel.dart';
|
||||||
import 'compiler.dart';
|
import 'compiler.dart';
|
||||||
import 'target.dart';
|
import 'target.dart';
|
||||||
|
|
||||||
|
@ -178,17 +179,14 @@ Future<CompilerResult> _compile(List<String> args,
|
||||||
var summaryPaths = options.summaryModules.keys.toList();
|
var summaryPaths = options.summaryModules.keys.toList();
|
||||||
var summaryModules = Map.fromIterables(
|
var summaryModules = Map.fromIterables(
|
||||||
summaryPaths.map(sourcePathToUri), options.summaryModules.values);
|
summaryPaths.map(sourcePathToUri), options.summaryModules.values);
|
||||||
|
var useAnalyzer = summaryPaths.any((s) => !s.endsWith('.dill'));
|
||||||
var sdkSummaryPath = argResults['dart-sdk-summary'] as String;
|
var sdkSummaryPath = argResults['dart-sdk-summary'] as String;
|
||||||
var librarySpecPath = argResults['libraries-file'] as String;
|
var librarySpecPath = argResults['libraries-file'] as String;
|
||||||
if (sdkSummaryPath == null) {
|
if (sdkSummaryPath == null) {
|
||||||
sdkSummaryPath = defaultSdkSummaryPath;
|
sdkSummaryPath =
|
||||||
|
useAnalyzer ? defaultAnalyzerSdkSummaryPath : defaultSdkSummaryPath;
|
||||||
librarySpecPath ??= defaultLibrarySpecPath;
|
librarySpecPath ??= defaultLibrarySpecPath;
|
||||||
}
|
}
|
||||||
var invalidSummary = summaryPaths.any((s) => !s.endsWith('.dill')) ||
|
|
||||||
!sdkSummaryPath.endsWith('.dill');
|
|
||||||
if (invalidSummary) {
|
|
||||||
throw StateError("Non-dill file detected in input: $summaryPaths");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (librarySpecPath == null) {
|
if (librarySpecPath == null) {
|
||||||
// TODO(jmesserly): the `isSupported` bit should be included in the SDK
|
// TODO(jmesserly): the `isSupported` bit should be included in the SDK
|
||||||
|
@ -207,12 +205,14 @@ Future<CompilerResult> _compile(List<String> args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useAnalyzer = useAnalyzer || !sdkSummaryPath.endsWith('.dill');
|
||||||
|
|
||||||
/// The .packages file path provided by the user.
|
/// The .packages file path provided by the user.
|
||||||
//
|
//
|
||||||
// TODO(jmesserly): the default location is based on the current working
|
// TODO(jmesserly): the default location is based on the current working
|
||||||
// directory, to match the behavior of dartanalyzer/dartdevc. However the
|
// directory, to match the behavior of dartanalyzer/dartdevc. However the
|
||||||
// Dart VM, CFE (and dart2js?) use the script file location instead. The
|
// Dart VM, CFE (and dart2js?) use the script file location instead. The
|
||||||
// difference may be due to the lack of a single entry point for Analyzer.
|
// difference may be due to the lack of a single entry point for DDC/Analyzer.
|
||||||
// Ultimately this is just the default behavior; in practice users call DDC
|
// Ultimately this is just the default behavior; in practice users call DDC
|
||||||
// through a build tool, which generally passes in `--packages=`.
|
// through a build tool, which generally passes in `--packages=`.
|
||||||
//
|
//
|
||||||
|
@ -244,7 +244,7 @@ Future<CompilerResult> _compile(List<String> args,
|
||||||
fe.WorkerInputComponent cachedSdkInput;
|
fe.WorkerInputComponent cachedSdkInput;
|
||||||
bool recordUsedInputs = argResults['used-inputs-file'] != null;
|
bool recordUsedInputs = argResults['used-inputs-file'] != null;
|
||||||
List<Uri> inputSummaries = summaryModules.keys.toList();
|
List<Uri> inputSummaries = summaryModules.keys.toList();
|
||||||
if (!useIncrementalCompiler) {
|
if (useAnalyzer || !useIncrementalCompiler) {
|
||||||
compilerState = await fe.initializeCompiler(
|
compilerState = await fe.initializeCompiler(
|
||||||
oldCompilerState,
|
oldCompilerState,
|
||||||
compileSdk,
|
compileSdk,
|
||||||
|
@ -306,8 +306,15 @@ Future<CompilerResult> _compile(List<String> args,
|
||||||
// `initializeCompiler`. Also we should be able to pass down Components for
|
// `initializeCompiler`. Also we should be able to pass down Components for
|
||||||
// SDK and summaries.
|
// SDK and summaries.
|
||||||
//
|
//
|
||||||
|
if (useAnalyzer && !identical(oldCompilerState, compilerState)) {
|
||||||
|
var opts = compilerState.processedOpts;
|
||||||
|
var converter = AnalyzerToKernel(sdkSummaryPath, summaryPaths);
|
||||||
|
opts.sdkSummaryComponent = converter.convertSdk();
|
||||||
|
opts.inputSummariesComponents = converter.convertSummaries();
|
||||||
|
}
|
||||||
|
|
||||||
fe.DdcResult result;
|
fe.DdcResult result;
|
||||||
if (!useIncrementalCompiler) {
|
if (useAnalyzer || !useIncrementalCompiler) {
|
||||||
result = await fe.compile(compilerState, inputs, diagnosticMessageHandler);
|
result = await fe.compile(compilerState, inputs, diagnosticMessageHandler);
|
||||||
} else {
|
} else {
|
||||||
compilerState.options.onDiagnostic = diagnosticMessageHandler;
|
compilerState.options.onDiagnostic = diagnosticMessageHandler;
|
||||||
|
@ -404,7 +411,7 @@ Future<CompilerResult> _compile(List<String> args,
|
||||||
|
|
||||||
if (recordUsedInputs) {
|
if (recordUsedInputs) {
|
||||||
Set<Uri> usedOutlines = Set<Uri>();
|
Set<Uri> usedOutlines = Set<Uri>();
|
||||||
if (useIncrementalCompiler) {
|
if (!useAnalyzer && useIncrementalCompiler) {
|
||||||
compilerState.incrementalCompiler
|
compilerState.incrementalCompiler
|
||||||
.updateNeededDillLibrariesWithHierarchy(result.classHierarchy, null);
|
.updateNeededDillLibrariesWithHierarchy(result.classHierarchy, null);
|
||||||
for (Library lib
|
for (Library lib
|
||||||
|
@ -530,6 +537,9 @@ final defaultSdkSummaryPath =
|
||||||
|
|
||||||
final defaultLibrarySpecPath = p.join(getSdkPath(), 'lib', 'libraries.json');
|
final defaultLibrarySpecPath = p.join(getSdkPath(), 'lib', 'libraries.json');
|
||||||
|
|
||||||
|
final defaultAnalyzerSdkSummaryPath =
|
||||||
|
p.join(getSdkPath(), 'lib', '_internal', 'ddc_sdk.sum');
|
||||||
|
|
||||||
bool _checkForDartMirrorsImport(Component component) {
|
bool _checkForDartMirrorsImport(Component component) {
|
||||||
for (var library in component.libraries) {
|
for (var library in component.libraries) {
|
||||||
if (library.isExternal || library.importUri.scheme == 'dart') continue;
|
if (library.isExternal || library.importUri.scheme == 'dart') continue;
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||||
/// corresponding Kernel summary module we imported it with.
|
/// corresponding Kernel summary module we imported it with.
|
||||||
final _importToSummary = Map<Library, Component>.identity();
|
final _importToSummary = Map<Library, Component>.identity();
|
||||||
|
|
||||||
/// Maps a Kernel summary to the JS import name for the module.
|
/// Maps a summary to the JS import name for the module.
|
||||||
final _summaryToModule = Map<Component, String>.identity();
|
final _summaryToModule = Map<Component, String>.identity();
|
||||||
|
|
||||||
/// The variable for the current catch clause
|
/// The variable for the current catch clause
|
||||||
|
|
|
@ -252,7 +252,8 @@ Iterable<Member> getRedirectingFactories(Field f) {
|
||||||
///
|
///
|
||||||
/// This is used to ignore synthetic mixin application classes.
|
/// This is used to ignore synthetic mixin application classes.
|
||||||
///
|
///
|
||||||
// TODO(jmesserly): consider replacing this with Kernel's mixin unrolling
|
// TODO(jmesserly): consider replacing this with Kernel's mixin unrolling once
|
||||||
|
// we don't have the Analyzer backend to maintain.
|
||||||
Class getSuperclassAndMixins(Class c, List<Class> mixins) {
|
Class getSuperclassAndMixins(Class c, List<Class> mixins) {
|
||||||
assert(mixins.isEmpty);
|
assert(mixins.isEmpty);
|
||||||
|
|
||||||
|
|
10
pkg/dev_compiler/web/index.html
Normal file
10
pkg/dev_compiler/web/index.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Dart Dev Compiler Console</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script defer src="main.dart.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
86
pkg/dev_compiler/web/main.dart
Executable file
86
pkg/dev_compiler/web/main.dart
Executable file
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env dart
|
||||||
|
// Copyright (c) 2016, 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.
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
library dev_compiler.web.main;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
|
import 'web_command.dart';
|
||||||
|
|
||||||
|
@JS(r'$setUpDartDevCompilerInBrowser')
|
||||||
|
external set setUpCompilerInBrowser(Function function);
|
||||||
|
|
||||||
|
Future<dynamic> _setUpCompilerInBrowser;
|
||||||
|
void main() {
|
||||||
|
var args = ['compile'];
|
||||||
|
|
||||||
|
// Avoid race condition when users try to call $setUpDartDevCompilerInBrowser
|
||||||
|
// before it is ready by installing the method immediately and making the body
|
||||||
|
// of the method async.
|
||||||
|
setUpCompilerInBrowser = allowInterop((String sdkUrl,
|
||||||
|
JSMap<String, String> summaryMap,
|
||||||
|
Function onCompileReady,
|
||||||
|
Function onError,
|
||||||
|
[Function onProgress]) async {
|
||||||
|
(await _setUpCompilerInBrowser)(
|
||||||
|
sdkUrl, summaryMap, onCompileReady, onError, onProgress);
|
||||||
|
});
|
||||||
|
_runCommand(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a single compile command, and returns an exit code.
|
||||||
|
_runCommand(List<String> args, {MessageHandler messageHandler}) {
|
||||||
|
try {
|
||||||
|
// TODO: Remove CommandRunner and args if possible. May run into issues
|
||||||
|
// with ArgResults or ArgParsers.
|
||||||
|
var runner = CommandRunner('dartdevc', 'Dart Development Compiler');
|
||||||
|
runner.addCommand(WebCompileCommand(messageHandler: messageHandler));
|
||||||
|
_setUpCompilerInBrowser = runner.run(args);
|
||||||
|
} catch (e, s) {
|
||||||
|
_handleError(e, s, args, messageHandler: messageHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles [error] in a uniform fashion. Calls [messageHandler] with messages.
|
||||||
|
_handleError(dynamic error, dynamic stackTrace, List<String> args,
|
||||||
|
{MessageHandler messageHandler}) {
|
||||||
|
messageHandler ??= print;
|
||||||
|
|
||||||
|
if (error is UsageException) {
|
||||||
|
// Incorrect usage, input file not found, etc.
|
||||||
|
messageHandler(error);
|
||||||
|
} else if (error is CompileErrorException) {
|
||||||
|
// Code has error(s) and failed to compile.
|
||||||
|
messageHandler(error);
|
||||||
|
} else {
|
||||||
|
// Anything else is likely a compiler bug.
|
||||||
|
//
|
||||||
|
// --unsafe-force-compile is a bit of a grey area, but it's nice not to
|
||||||
|
// crash while compiling
|
||||||
|
// (of course, output code may crash, if it had errors).
|
||||||
|
//
|
||||||
|
messageHandler("");
|
||||||
|
messageHandler("We're sorry, you've found a bug in our compiler.");
|
||||||
|
messageHandler("You can report this bug at:");
|
||||||
|
messageHandler(
|
||||||
|
" https://github.com/dart-lang/sdk/issues/labels/web-dev-compiler");
|
||||||
|
messageHandler("");
|
||||||
|
messageHandler(
|
||||||
|
"Please include the information below in your report, along with");
|
||||||
|
messageHandler(
|
||||||
|
"any other information that may help us track it down. Thanks!");
|
||||||
|
messageHandler("");
|
||||||
|
messageHandler(" dartdevc arguments: " + args.join(' '));
|
||||||
|
messageHandler("");
|
||||||
|
messageHandler("```");
|
||||||
|
messageHandler(error);
|
||||||
|
messageHandler(stackTrace);
|
||||||
|
messageHandler("```");
|
||||||
|
}
|
||||||
|
}
|
313
pkg/dev_compiler/web/web_command.dart
Normal file
313
pkg/dev_compiler/web/web_command.dart
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
// Copyright (c) 2016, 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.
|
||||||
|
@JS()
|
||||||
|
library dev_compiler.web.web_command;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
import 'dart:html' show HttpRequest;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
|
||||||
|
import 'package:analyzer/file_system/memory_file_system.dart'
|
||||||
|
show MemoryResourceProvider;
|
||||||
|
import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
|
||||||
|
import 'package:analyzer/src/summary/package_bundle_reader.dart'
|
||||||
|
show SummaryDataStore;
|
||||||
|
import 'package:analyzer/src/dart/resolver/scope.dart' show Scope;
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
|
||||||
|
import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions;
|
||||||
|
import 'package:dev_compiler/src/analyzer/command.dart';
|
||||||
|
import 'package:dev_compiler/src/analyzer/driver.dart';
|
||||||
|
import 'package:dev_compiler/src/analyzer/module_compiler.dart';
|
||||||
|
|
||||||
|
import 'package:dev_compiler/src/compiler/module_builder.dart';
|
||||||
|
import 'package:js/js.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
|
typedef void MessageHandler(Object message);
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
@anonymous
|
||||||
|
class JSIterator<V> {}
|
||||||
|
|
||||||
|
@JS('Map')
|
||||||
|
class JSMap<K, V> {
|
||||||
|
external V get(K v);
|
||||||
|
external set(K k, V v);
|
||||||
|
external JSIterator<K> keys();
|
||||||
|
external JSIterator<V> values();
|
||||||
|
external int get size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JS('Array.from')
|
||||||
|
external List<V> iteratorToList<V>(JSIterator<V> iterator);
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
@anonymous
|
||||||
|
class CompileResult {
|
||||||
|
external factory CompileResult(
|
||||||
|
{String code, List<String> errors, bool isValid});
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef CompileModule(String imports, String body, String libraryName,
|
||||||
|
String existingLibrary, String fileName);
|
||||||
|
|
||||||
|
/// The command for invoking the modular compiler.
|
||||||
|
class WebCompileCommand extends Command {
|
||||||
|
@override
|
||||||
|
get name => 'compile';
|
||||||
|
|
||||||
|
@override
|
||||||
|
get description => 'Compile a set of Dart files into a JavaScript module.';
|
||||||
|
final MessageHandler messageHandler;
|
||||||
|
|
||||||
|
WebCompileCommand({MessageHandler messageHandler})
|
||||||
|
: this.messageHandler = messageHandler ?? print {
|
||||||
|
ddcArgParser(argParser: argParser, help: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function run() {
|
||||||
|
return requestSummaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Null> requestSummaries(String sdkUrl, JSMap<String, String> summaryMap,
|
||||||
|
Function onCompileReady, Function onError, Function onProgress) async {
|
||||||
|
var sdkRequest;
|
||||||
|
var progress = 0;
|
||||||
|
// Add 1 to the count for the SDK summary.
|
||||||
|
var total = summaryMap.size + 1;
|
||||||
|
// No need to report after every summary is loaded. Posting about 100
|
||||||
|
// progress updates should be more than sufficient for users to understand
|
||||||
|
// how long loading will take.
|
||||||
|
num progressDelta = math.max(total / 100, 1);
|
||||||
|
num nextProgressToReport = 0;
|
||||||
|
maybeReportProgress() {
|
||||||
|
if (nextProgressToReport > progress && progress != total) return;
|
||||||
|
nextProgressToReport += progressDelta;
|
||||||
|
if (onProgress != null) onProgress(progress, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sdkRequest = await HttpRequest.request(sdkUrl,
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
mimeType: "application/octet-stream",
|
||||||
|
withCredentials: true);
|
||||||
|
} catch (error) {
|
||||||
|
onError('Dart sdk summaries failed to load: $error. url: $sdkUrl');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
progress++;
|
||||||
|
maybeReportProgress();
|
||||||
|
|
||||||
|
var sdkBytes = (sdkRequest.response as ByteBuffer).asUint8List();
|
||||||
|
|
||||||
|
// Map summary URLs to HttpRequests.
|
||||||
|
|
||||||
|
var summaryRequests =
|
||||||
|
iteratorToList(summaryMap.values()).map((String summaryUrl) async {
|
||||||
|
var request = await HttpRequest.request(summaryUrl,
|
||||||
|
responseType: "arraybuffer", mimeType: "application/octet-stream");
|
||||||
|
progress++;
|
||||||
|
maybeReportProgress();
|
||||||
|
return request;
|
||||||
|
}).toList();
|
||||||
|
try {
|
||||||
|
var summaryResponses = await Future.wait(summaryRequests);
|
||||||
|
// Map summary responses to summary bytes.
|
||||||
|
List<List<int>> summaryBytes = summaryResponses
|
||||||
|
.map((response) => (response.response as ByteBuffer).asUint8List())
|
||||||
|
.toList();
|
||||||
|
onCompileReady(setUpCompile(
|
||||||
|
sdkBytes, summaryBytes, iteratorToList(summaryMap.keys())));
|
||||||
|
} catch (error) {
|
||||||
|
onError('Summaries failed to load: $error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Function> setUpCompile(List<int> sdkBytes, List<List<int>> summaryBytes,
|
||||||
|
List<String> moduleIds) {
|
||||||
|
var dartSdkSummaryPath = '/dart-sdk/lib/_internal/web_sdk.sum';
|
||||||
|
|
||||||
|
var resources = MemoryResourceProvider()
|
||||||
|
..newFileWithBytes(dartSdkSummaryPath, sdkBytes);
|
||||||
|
|
||||||
|
var options = AnalyzerOptions.basic(
|
||||||
|
dartSdkPath: '/dart-sdk', dartSdkSummaryPath: dartSdkSummaryPath);
|
||||||
|
|
||||||
|
var summaryData = SummaryDataStore([], resourceProvider: resources);
|
||||||
|
var compilerOptions = CompilerOptions.fromArguments(argResults);
|
||||||
|
compilerOptions.replCompile = true;
|
||||||
|
compilerOptions.libraryRoot = '/';
|
||||||
|
for (var i = 0; i < summaryBytes.length; i++) {
|
||||||
|
var bytes = summaryBytes[i];
|
||||||
|
|
||||||
|
// Packages with no dart source files will have empty invalid summaries.
|
||||||
|
if (bytes.isEmpty) continue;
|
||||||
|
|
||||||
|
var moduleId = moduleIds[i];
|
||||||
|
var url = '/$moduleId.api.ds';
|
||||||
|
summaryData.addBundle(url, PackageBundle.fromBuffer(bytes));
|
||||||
|
compilerOptions.summaryModules[url] = moduleId;
|
||||||
|
}
|
||||||
|
options.analysisRoot = '/web-compile-root';
|
||||||
|
options.fileResolvers = [ResourceUriResolver(resources)];
|
||||||
|
options.resourceProvider = resources;
|
||||||
|
|
||||||
|
var driver = CompilerAnalysisDriver(options, summaryData: summaryData);
|
||||||
|
|
||||||
|
var resolveFn = (String url) {
|
||||||
|
var packagePrefix = 'package:';
|
||||||
|
var uri = Uri.parse(url);
|
||||||
|
var base = p.basename(url);
|
||||||
|
var parts = uri.pathSegments;
|
||||||
|
var match;
|
||||||
|
int bestScore = 0;
|
||||||
|
for (var candidate in summaryData.uriToSummaryPath.keys) {
|
||||||
|
if (p.basename(candidate) != base) continue;
|
||||||
|
List<String> candidateParts = p.dirname(candidate).split('/');
|
||||||
|
var first = candidateParts.first;
|
||||||
|
|
||||||
|
// Process and strip "package:" prefix.
|
||||||
|
if (first.startsWith(packagePrefix)) {
|
||||||
|
first = first.substring(packagePrefix.length);
|
||||||
|
candidateParts[0] = first;
|
||||||
|
// Handle convention that directory foo/bar/baz is given package name
|
||||||
|
// foo.bar.baz
|
||||||
|
if (first.contains('.')) {
|
||||||
|
candidateParts = (first.split('.'))..addAll(candidateParts.skip(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If file name and extension don't match... give up.
|
||||||
|
int i = parts.length - 1;
|
||||||
|
int j = candidateParts.length - 1;
|
||||||
|
|
||||||
|
int score = 1;
|
||||||
|
// Greedy algorithm finding matching path segments from right to left
|
||||||
|
// skipping segments on the candidate path unless the target path
|
||||||
|
// segment is named lib.
|
||||||
|
while (i >= 0 && j >= 0) {
|
||||||
|
if (parts[i] == candidateParts[j]) {
|
||||||
|
i--;
|
||||||
|
j--;
|
||||||
|
score++;
|
||||||
|
if (j == 0 && i == 0) {
|
||||||
|
// Arbitrary bonus if we matched all parts of the input
|
||||||
|
// and used up all parts of the output.
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// skip unmatched lib directories from the input
|
||||||
|
// otherwise skip unmatched parts of the candidate.
|
||||||
|
if (parts[i] == 'lib') {
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > bestScore) {
|
||||||
|
match = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompileModule compileFn = (String imports, String body, String libraryName,
|
||||||
|
String existingLibrary, String fileName) {
|
||||||
|
// Instead of returning a single function, return a pair of functions.
|
||||||
|
// Create a new virtual File that contains the given Dart source.
|
||||||
|
String sourceCode;
|
||||||
|
if (existingLibrary == null) {
|
||||||
|
sourceCode = imports + body;
|
||||||
|
} else {
|
||||||
|
var dir = p.dirname(existingLibrary);
|
||||||
|
// Need to pull in all the imports from the existing library and
|
||||||
|
// re-export all privates as privates in this library.
|
||||||
|
// Assumption: summaries are available for all libraries, including any
|
||||||
|
// source files that were compiled; we do not need to reconstruct any
|
||||||
|
// summary data here.
|
||||||
|
var unlinked = driver.summaryData.unlinkedMap[existingLibrary];
|
||||||
|
if (unlinked == null) {
|
||||||
|
throw "Unable to get library element for `$existingLibrary`.";
|
||||||
|
}
|
||||||
|
var sb = StringBuffer(imports);
|
||||||
|
sb.write('\n');
|
||||||
|
|
||||||
|
// TODO(jacobr): we need to add a proper Analyzer flag specifing that
|
||||||
|
// cross-library privates should be in scope instead of this hack.
|
||||||
|
// We set the private name prefix for scope resolution to an invalid
|
||||||
|
// character code so that the analyzer ignores normal Dart private
|
||||||
|
// scoping rules for top level names allowing REPL users to access
|
||||||
|
// privates in arbitrary libraries. The downside of this scheme is it is
|
||||||
|
// possible to get errors if privates in the current library and
|
||||||
|
// imported libraries happen to have exactly the same name.
|
||||||
|
Scope.PRIVATE_NAME_PREFIX = -1;
|
||||||
|
|
||||||
|
// We emulate running code in the context of an existing library by
|
||||||
|
// importing that library and all libraries it imports.
|
||||||
|
sb.write('import ${json.encode(existingLibrary)};\n');
|
||||||
|
|
||||||
|
for (var import in unlinked.imports) {
|
||||||
|
if (import.uri == null || import.isImplicit) continue;
|
||||||
|
var uri = import.uri;
|
||||||
|
// dart: and package: uris are not relative but the path package
|
||||||
|
// thinks they are. We have to provide absolute uris as our library
|
||||||
|
// has a different directory than the library we are pretending to be.
|
||||||
|
if (p.isRelative(uri) &&
|
||||||
|
!uri.startsWith('package:') &&
|
||||||
|
!uri.startsWith('dart:')) {
|
||||||
|
uri = p.normalize(p.join(dir, uri));
|
||||||
|
}
|
||||||
|
sb.write('import ${json.encode(uri)}');
|
||||||
|
if (import.prefixReference != 0) {
|
||||||
|
var prefix = unlinked.references[import.prefixReference].name;
|
||||||
|
sb.write(' as $prefix');
|
||||||
|
}
|
||||||
|
for (var combinator in import.combinators) {
|
||||||
|
if (combinator.shows.isNotEmpty) {
|
||||||
|
sb.write(' show ${combinator.shows.join(', ')}');
|
||||||
|
} else if (combinator.hides.isNotEmpty) {
|
||||||
|
sb.write(' hide ${combinator.hides.join(', ')}');
|
||||||
|
} else {
|
||||||
|
throw 'Unexpected element combinator';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.write(';\n');
|
||||||
|
}
|
||||||
|
sb.write(body);
|
||||||
|
sourceCode = sb.toString();
|
||||||
|
}
|
||||||
|
resources.newFile(fileName, sourceCode);
|
||||||
|
|
||||||
|
var name = p.toUri(libraryName).toString();
|
||||||
|
compilerOptions.moduleName = name;
|
||||||
|
JSModuleFile module =
|
||||||
|
compileWithAnalyzer(driver, [fileName], options, compilerOptions);
|
||||||
|
|
||||||
|
var moduleCode = '';
|
||||||
|
if (module.isValid) {
|
||||||
|
moduleCode =
|
||||||
|
module.getCode(ModuleFormat.legacyConcat, name, name + '.map').code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompileResult(
|
||||||
|
code: moduleCode, isValid: module.isValid, errors: module.errors);
|
||||||
|
};
|
||||||
|
|
||||||
|
return [allowInterop(compileFn), allowInterop(resolveFn)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Thrown when the input source code has errors.
|
||||||
|
class CompileErrorException implements Exception {
|
||||||
|
@override
|
||||||
|
toString() => '\nPlease fix all errors before compiling (warnings are okay).';
|
||||||
|
}
|
24
sdk/BUILD.gn
24
sdk/BUILD.gn
|
@ -785,7 +785,10 @@ copy("copy_dev_compiler_js_es6_kernel") {
|
||||||
|
|
||||||
# Copies all of the JS artifacts needed by DDC.
|
# Copies all of the JS artifacts needed by DDC.
|
||||||
group("copy_dev_compiler_js") {
|
group("copy_dev_compiler_js") {
|
||||||
visibility = [ ":copy_dev_compiler_sdk" ]
|
visibility = [
|
||||||
|
":copy_dev_compiler_sdk",
|
||||||
|
":copy_dev_compiler_tools",
|
||||||
|
]
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":copy_dev_compiler_js_amd",
|
":copy_dev_compiler_js_amd",
|
||||||
":copy_dev_compiler_js_amd_kernel",
|
":copy_dev_compiler_js_amd_kernel",
|
||||||
|
@ -796,12 +799,31 @@ group("copy_dev_compiler_js") {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This rule copies tools to go along with ddc.
|
||||||
|
copy("copy_dev_compiler_tools") {
|
||||||
|
visibility = [ ":copy_dev_compiler_sdk" ]
|
||||||
|
deps = [
|
||||||
|
":copy_dev_compiler_js",
|
||||||
|
"../utils/dartdevc:dartdevc_web",
|
||||||
|
"../utils/dartdevc:stack_trace_mapper",
|
||||||
|
]
|
||||||
|
dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
|
||||||
|
sources = [
|
||||||
|
"$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
|
||||||
|
"$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
|
||||||
|
]
|
||||||
|
outputs = [
|
||||||
|
"$root_out_dir/dart-sdk/lib/dev_compiler/web/{{source_file_part}}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
# This is the main rule for copying ddc's dependencies to lib/
|
# This is the main rule for copying ddc's dependencies to lib/
|
||||||
group("copy_dev_compiler_sdk") {
|
group("copy_dev_compiler_sdk") {
|
||||||
visibility = [ ":create_full_sdk" ]
|
visibility = [ ":create_full_sdk" ]
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":copy_dev_compiler_js",
|
":copy_dev_compiler_js",
|
||||||
":copy_dev_compiler_summary",
|
":copy_dev_compiler_summary",
|
||||||
|
":copy_dev_compiler_tools",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,6 @@ if (target_os != current_os && target_os == "fuchsia") {
|
||||||
# will not find the actual binary.
|
# will not find the actual binary.
|
||||||
action("copy_dart_nnbd") {
|
action("copy_dart_nnbd") {
|
||||||
visibility = [ ":create_common_sdk_nnbd" ]
|
visibility = [ ":create_common_sdk_nnbd" ]
|
||||||
|
|
||||||
# TODO(rnystrom): This probably needs to be forked for NNBD.
|
# TODO(rnystrom): This probably needs to be forked for NNBD.
|
||||||
dart_label = "../runtime/bin:dart"
|
dart_label = "../runtime/bin:dart"
|
||||||
deps = [
|
deps = [
|
||||||
|
@ -806,14 +805,35 @@ copy("copy_dev_compiler_js_es6_kernel_nnbd") {
|
||||||
|
|
||||||
# Copies all of the JS artifacts needed by DDC.
|
# Copies all of the JS artifacts needed by DDC.
|
||||||
group("copy_dev_compiler_js_nnbd") {
|
group("copy_dev_compiler_js_nnbd") {
|
||||||
visibility = [ ":copy_dev_compiler_sdk_nnbd" ]
|
visibility = [
|
||||||
|
":copy_dev_compiler_sdk_nnbd",
|
||||||
|
":copy_dev_compiler_tools_nnbd",
|
||||||
|
]
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":copy_dev_compiler_js_amd_kernel_nnbd",
|
|
||||||
":copy_dev_compiler_js_amd_nnbd",
|
":copy_dev_compiler_js_amd_nnbd",
|
||||||
":copy_dev_compiler_js_common_kernel_nnbd",
|
":copy_dev_compiler_js_amd_kernel_nnbd",
|
||||||
":copy_dev_compiler_js_common_nnbd",
|
":copy_dev_compiler_js_common_nnbd",
|
||||||
":copy_dev_compiler_js_es6_kernel_nnbd",
|
":copy_dev_compiler_js_common_kernel_nnbd",
|
||||||
":copy_dev_compiler_js_es6_nnbd",
|
":copy_dev_compiler_js_es6_nnbd",
|
||||||
|
":copy_dev_compiler_js_es6_kernel_nnbd",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# This rule copies tools to go along with ddc.
|
||||||
|
copy("copy_dev_compiler_tools_nnbd") {
|
||||||
|
visibility = [ ":copy_dev_compiler_sdk_nnbd" ]
|
||||||
|
deps = [
|
||||||
|
":copy_dev_compiler_js_nnbd",
|
||||||
|
"../utils/dartdevc:dartdevc_web",
|
||||||
|
"../utils/dartdevc:stack_trace_mapper",
|
||||||
|
]
|
||||||
|
dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
|
||||||
|
sources = [
|
||||||
|
"$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
|
||||||
|
"$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
|
||||||
|
]
|
||||||
|
outputs = [
|
||||||
|
"$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/web/{{source_file_part}}",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,6 +843,7 @@ group("copy_dev_compiler_sdk_nnbd") {
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":copy_dev_compiler_js_nnbd",
|
":copy_dev_compiler_js_nnbd",
|
||||||
":copy_dev_compiler_summary_nnbd",
|
":copy_dev_compiler_summary_nnbd",
|
||||||
|
":copy_dev_compiler_tools_nnbd",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,8 +1021,8 @@ group("create_common_sdk_nnbd") {
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":copy_analysis_summaries_nnbd",
|
":copy_analysis_summaries_nnbd",
|
||||||
":copy_api_readme_nnbd",
|
":copy_api_readme_nnbd",
|
||||||
":copy_dart2native_nnbd",
|
|
||||||
":copy_dart_nnbd",
|
":copy_dart_nnbd",
|
||||||
|
":copy_dart2native_nnbd",
|
||||||
":copy_dartdoc_files_nnbd",
|
":copy_dartdoc_files_nnbd",
|
||||||
":copy_headers_nnbd",
|
":copy_headers_nnbd",
|
||||||
":copy_libraries_dart_nnbd",
|
":copy_libraries_dart_nnbd",
|
||||||
|
@ -1065,4 +1086,4 @@ group("create_sdk_with_abi_versions_nnbd") {
|
||||||
":copy_abi_dill_files_nnbd",
|
":copy_abi_dill_files_nnbd",
|
||||||
":create_sdk_nnbd",
|
":create_sdk_nnbd",
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
Reference in a new issue