mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:31:50 +00:00
fix some issues with compiling the kernel SDK
- fix all usage of `.name` when `.name.name` is required - fix handling of inline-JS in the SDK - fix casts on SDK nodes Change-Id: Ic48e0b77e6e03515f16b8c30d3e274abbe2ed272 Reviewed-on: https://dart-review.googlesource.com/34540 Reviewed-by: Vijay Menon <vsm@google.com> Commit-Queue: Jenny Messerly <jmesserly@google.com>
This commit is contained in:
parent
a767fc81d2
commit
a052d8e0dc
|
@ -3898,7 +3898,8 @@ class CodeGenerator extends Object
|
|||
|
||||
/// Emits code for the `JS(...)` macro.
|
||||
JS.Node _emitForeignJS(MethodInvocation node, Element e) {
|
||||
if (isInlineJS(e)) {
|
||||
if (!isInlineJS(e)) return null;
|
||||
|
||||
var args = node.argumentList.arguments;
|
||||
// arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer`
|
||||
var code = args[1];
|
||||
|
@ -3930,8 +3931,7 @@ class CodeGenerator extends Object
|
|||
var constructorPattern = new RegExp("new [A-Z][A-Za-z]+\\(");
|
||||
if (constructorPattern.matchAsPrefix(source) != null) {
|
||||
var containingClass = node.parent;
|
||||
while (
|
||||
containingClass != null && containingClass is! ClassDeclaration) {
|
||||
while (containingClass != null && containingClass is! ClassDeclaration) {
|
||||
containingClass = containingClass.parent;
|
||||
}
|
||||
if (containingClass is ClassDeclaration &&
|
||||
|
@ -3984,8 +3984,6 @@ class CodeGenerator extends Object
|
|||
result is JS.Throw && node.parent is ExpressionStatement);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
JS.Expression visitFunctionExpressionInvocation(
|
||||
|
|
|
@ -658,7 +658,7 @@ class ProgramCompiler
|
|||
var jsParams = _emitFormalParameters(ctor.function);
|
||||
var ctorBody = <JS.Statement>[];
|
||||
if (mixinCtor != null) ctorBody.add(mixinCtor);
|
||||
if (ctor.name != '' || hasUnnamedSuper) {
|
||||
if (ctor.name.name != '' || hasUnnamedSuper) {
|
||||
ctorBody.add(
|
||||
_emitSuperConstructorCall(className, ctor.name.name, jsParams));
|
||||
}
|
||||
|
@ -2029,12 +2029,12 @@ class ProgramCompiler
|
|||
var lazyFields = <Field>[];
|
||||
for (var field in fields) {
|
||||
// Skip our magic undefined constant.
|
||||
if (field.name == 'undefined') continue;
|
||||
if (field.name.name == 'undefined') continue;
|
||||
|
||||
var init = field.initializer;
|
||||
if (init == null ||
|
||||
init is BasicLiteral ||
|
||||
_isJSInvocation(init) ||
|
||||
_isInlineJSCall(init) ||
|
||||
init is ConstructorInvocation &&
|
||||
isSdkInternalRuntime(init.target.enclosingLibrary)) {
|
||||
_moduleItems.add(js.statement('# = #;', [
|
||||
|
@ -2048,9 +2048,6 @@ class ProgramCompiler
|
|||
return _emitLazyFields(_currentLibrary, lazyFields);
|
||||
}
|
||||
|
||||
bool _isJSInvocation(Expression expr) =>
|
||||
expr is StaticInvocation && isInlineJS(expr.target);
|
||||
|
||||
JS.Statement _emitLazyFields(NamedNode target, Iterable<Field> fields) {
|
||||
var accessors = <JS.Method>[];
|
||||
for (var field in fields) {
|
||||
|
@ -3032,8 +3029,14 @@ class ProgramCompiler
|
|||
defaultStatement(Statement node) => _emitInvalidNode(node).toStatement();
|
||||
|
||||
@override
|
||||
visitExpressionStatement(ExpressionStatement node) =>
|
||||
_visitAndMarkExpression(node.expression).toStatement();
|
||||
visitExpressionStatement(ExpressionStatement node) {
|
||||
var expr = node.expression;
|
||||
if (_isInlineJSCall(expr)) {
|
||||
var inlineJS = _emitInlineJSCode(expr);
|
||||
return inlineJS is JS.Expression ? inlineJS.toStatement() : inlineJS;
|
||||
}
|
||||
return _visitAndMarkExpression(expr).toStatement();
|
||||
}
|
||||
|
||||
@override
|
||||
visitBlock(Block node) =>
|
||||
|
@ -4096,13 +4099,11 @@ class ProgramCompiler
|
|||
|
||||
@override
|
||||
visitStaticInvocation(StaticInvocation node) {
|
||||
var result = _emitForeignJS(node);
|
||||
if (result != null) return result;
|
||||
if (node.target.isFactory) {
|
||||
return _emitFactoryInvocation(node);
|
||||
}
|
||||
var target = node.target;
|
||||
if (target?.name == 'extensionSymbol' &&
|
||||
if (isInlineJS(target)) return _emitInlineJSCode(node);
|
||||
if (target.isFactory) return _emitFactoryInvocation(node);
|
||||
|
||||
if (target.name.name == 'extensionSymbol' &&
|
||||
isSdkInternalRuntime(target.enclosingLibrary)) {
|
||||
var args = node.arguments;
|
||||
var firstArg = args.positional.length == 1 ? args.positional[0] : null;
|
||||
|
@ -4158,17 +4159,21 @@ class ProgramCompiler
|
|||
}
|
||||
|
||||
/// Emits code for the `JS(...)` macro.
|
||||
JS.Expression _emitForeignJS(StaticInvocation node) {
|
||||
if (!isInlineJS(node.target)) return null;
|
||||
JS.Node _emitInlineJSCode(StaticInvocation node) {
|
||||
var args = node.arguments.positional;
|
||||
// arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer`
|
||||
var code = args[1];
|
||||
List<Expression> templateArgs;
|
||||
String source;
|
||||
if (code is StringConcatenation) {
|
||||
if (code.expressions.every((e) => e is StringLiteral)) {
|
||||
templateArgs = args.skip(2).toList();
|
||||
source = code.expressions.map((e) => (e as StringLiteral).value).join();
|
||||
} else {
|
||||
if (args.length > 2) {
|
||||
throw new ArgumentError(
|
||||
"Can't mix template args and string interpolation in JS calls.");
|
||||
"Can't mix template args and string interpolation in JS calls: "
|
||||
"`$node`");
|
||||
}
|
||||
templateArgs = <Expression>[];
|
||||
source = code.expressions.map((expression) {
|
||||
|
@ -4179,6 +4184,7 @@ class ProgramCompiler
|
|||
return '#';
|
||||
}
|
||||
}).join();
|
||||
}
|
||||
} else {
|
||||
templateArgs = args.skip(2).toList();
|
||||
source = (code as StringLiteral).value;
|
||||
|
@ -4209,7 +4215,7 @@ class ProgramCompiler
|
|||
if (arg is StaticInvocation) {
|
||||
var target = arg.target;
|
||||
var positional = arg.arguments.positional;
|
||||
if (target.name == 'getGenericClass' &&
|
||||
if (target.name.name == 'getGenericClass' &&
|
||||
isSdkInternalRuntime(target.enclosingLibrary) &&
|
||||
positional.length == 1) {
|
||||
var typeArg = positional[0];
|
||||
|
@ -4364,9 +4370,9 @@ class ProgramCompiler
|
|||
case 'Map':
|
||||
case 'HashMap':
|
||||
case 'LinkedHashMap':
|
||||
if (ctor.name == '') {
|
||||
if (ctor.name.name == '') {
|
||||
return js.call('new #.new()', _emitMapImplType(type));
|
||||
} else if (ctor.name == 'identity') {
|
||||
} else if (ctor.name.name == 'identity') {
|
||||
return js.call(
|
||||
'new #.new()', _emitMapImplType(type, identity: true));
|
||||
}
|
||||
|
@ -4374,15 +4380,15 @@ class ProgramCompiler
|
|||
case 'Set':
|
||||
case 'HashSet':
|
||||
case 'LinkedHashSet':
|
||||
if (ctor.name == '') {
|
||||
if (ctor.name.name == '') {
|
||||
return js.call('new #.new()', _emitSetImplType(type));
|
||||
} else if (ctor.name == 'identity') {
|
||||
} else if (ctor.name.name == 'identity') {
|
||||
return js.call(
|
||||
'new #.new()', _emitSetImplType(type, identity: true));
|
||||
}
|
||||
break;
|
||||
case 'List':
|
||||
if (ctor.name == '' && type is InterfaceType) {
|
||||
if (ctor.name.name == '' && type is InterfaceType) {
|
||||
return _emitList(type.typeArguments[0], []);
|
||||
}
|
||||
break;
|
||||
|
@ -4515,9 +4521,9 @@ class ProgramCompiler
|
|||
@override
|
||||
visitAsExpression(AsExpression node) {
|
||||
Expression fromExpr = node.operand;
|
||||
var from = fromExpr.getStaticType(types);
|
||||
var to = node.type;
|
||||
var jsFrom = _visitAndMarkExpression(fromExpr);
|
||||
var from = fromExpr.getStaticType(types);
|
||||
|
||||
// If the check was put here by static analysis to ensure soundness, we
|
||||
// can't skip it. For example, one could implement covariant generic caller
|
||||
|
@ -4536,10 +4542,6 @@ class ProgramCompiler
|
|||
// c.add('hi);
|
||||
// }
|
||||
//
|
||||
// NOTE: due to implementation details, we do not currently reify the the
|
||||
// `C<T>.add` check in CoercionReifier, so it does not reach this point;
|
||||
// rather we check for it explicitly when emitting methods and fields.
|
||||
// However we do reify the `c.f` check, so we must not eliminate it.
|
||||
var isTypeError = node.isTypeError;
|
||||
if (!isTypeError && types.isSubtypeOf(from, to)) return jsFrom;
|
||||
|
||||
|
@ -4865,13 +4867,12 @@ bool _isInlineJSFunction(Statement body) {
|
|||
if (statements.length != 1) return false;
|
||||
body = statements[0];
|
||||
}
|
||||
if (body is ReturnStatement) {
|
||||
var e = body.expression;
|
||||
return e is MethodInvocation && isInlineJS(e.interfaceTarget);
|
||||
}
|
||||
return false;
|
||||
return body is ReturnStatement && _isInlineJSCall(body.expression);
|
||||
}
|
||||
|
||||
bool _isInlineJSCall(Expression expr) =>
|
||||
expr is StaticInvocation && isInlineJS(expr.target);
|
||||
|
||||
/// Return true if this is one of the methods/properties on all Dart Objects
|
||||
/// (toString, hashCode, noSuchMethod, runtimeType).
|
||||
///
|
||||
|
|
|
@ -248,5 +248,5 @@ Expression getInvocationReceiver(InvocationExpression node) =>
|
|||
|
||||
bool isInlineJS(Member e) =>
|
||||
e is Procedure &&
|
||||
e.name == 'JS' &&
|
||||
e.name.name == 'JS' &&
|
||||
e.enclosingLibrary.importUri.toString() == 'dart:_foreign_helper';
|
||||
|
|
|
@ -164,13 +164,6 @@ class NullableInference extends ExpressionVisitor<bool> {
|
|||
var target = node.target;
|
||||
if (target == types.coreTypes.identicalProcedure) return false;
|
||||
if (isInlineJS(target)) {
|
||||
// Fix types for JS builtin calls.
|
||||
//
|
||||
// This code was taken from analyzer. It's not super sophisticated:
|
||||
// only looks for the type name in dart:core, so we just copy it here.
|
||||
//
|
||||
// TODO(jmesserly): we'll likely need something that can handle a wider
|
||||
// variety of types, especially when we get to JS interop.
|
||||
var args = node.arguments.positional;
|
||||
var first = args.isNotEmpty ? args.first : null;
|
||||
if (first is StringLiteral) {
|
||||
|
|
|
@ -577,7 +577,7 @@ class GenericFunctionType extends AbstractFunctionType {
|
|||
var typeBounds = instantiateTypeBounds(typeFormals);
|
||||
for (int i = 0, n = typeFormals.length; i < n; i++) {
|
||||
if (i != 0) s += ", ";
|
||||
s += JS('String', '#[#].name', typeFormals, i);
|
||||
s += JS<String>('!', '#[#].name', typeFormals, i);
|
||||
var typeBound = typeBounds[i];
|
||||
if (!identical(typeBound, _dynamic)) {
|
||||
s += " extends $typeBound";
|
||||
|
|
|
@ -106,7 +106,7 @@ library dart._foreign_helper;
|
|||
*/
|
||||
// Add additional optional arguments if needed. The method is treated internally
|
||||
// as a variable argument method.
|
||||
JS(String typeDescription, String codeTemplate,
|
||||
T JS<T>(String typeDescription, String codeTemplate,
|
||||
[arg0,
|
||||
arg1,
|
||||
arg2,
|
||||
|
|
|
@ -202,7 +202,7 @@ class JSNumber extends Interceptor implements int, double {
|
|||
int exponent = JS("int", "+#", match[3]);
|
||||
if (match[2] != null) {
|
||||
result = JS('String', '# + #', result, match[2]);
|
||||
exponent -= JS('int', '#.length', match[2]);
|
||||
exponent -= JS<int>('!', '#.length', match[2]);
|
||||
}
|
||||
return result + "0" * exponent;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue