diff --git a/pkg/_fe_analyzer_shared/lib/src/util/runtimes.dart b/pkg/_fe_analyzer_shared/lib/src/util/runtimes.dart index d2d6e5230a71..944fbfff940a 100644 --- a/pkg/_fe_analyzer_shared/lib/src/util/runtimes.dart +++ b/pkg/_fe_analyzer_shared/lib/src/util/runtimes.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:isolate'; +import 'dart:typed_data'; /// Whether the current runtime can register kernel blobs and launch kernel /// isolates. @@ -11,10 +12,17 @@ bool get isKernelRuntime => _isKernelRuntime ??= _checkForKernelRuntime(); bool? _isKernelRuntime; bool _checkForKernelRuntime() { + // `createUriForKernelBlob` throws `UnsupportedError` if kernel blobs are not + // supported at all. We don't actually want to register kernel so pass + // invalid kernel, an empty list, resulting in an `ArgumentError` if kernel + // blobs are supported. try { - (Isolate.current as dynamic).createUriForKernelBlob; - return true; - } catch (_) { + (Isolate.current as dynamic) + .createUriForKernelBlob(new Uint8List.fromList(const [])); + throw new StateError('Expected failure.'); + } on UnsupportedError { return false; + } on ArgumentError { + return true; } } diff --git a/pkg/dart2wasm/lib/transformers.dart b/pkg/dart2wasm/lib/transformers.dart index b8d896959b4c..a713e61d784e 100644 --- a/pkg/dart2wasm/lib/transformers.dart +++ b/pkg/dart2wasm/lib/transformers.dart @@ -30,20 +30,32 @@ class _WasmTransformer extends Transformer { Member? _currentMember; StaticTypeContext? _cachedTypeContext; + final Library _coreLibrary; final InterfaceType _nonNullableTypeType; - final Class _wasmBaseClass; + + final Class _completerClass; + final Class _streamControllerClass; final Class _wasmArrayClass; + final Class _wasmBaseClass; + + final Procedure _completerComplete; + final Procedure _completerConstructor; + final Procedure _completerGetFuture; + final Procedure _streamControllerAdd; + final Procedure _streamControllerAddError; + final Procedure _streamControllerAddStream; + final Procedure _streamControllerClose; + final Procedure _streamControllerConstructor; + final Procedure _streamControllerGetHasListener; + final Procedure _streamControllerGetIsPaused; + final Procedure _streamControllerGetStream; + final Procedure _streamControllerSetOnCancel; + final Procedure _streamControllerSetOnListen; + final Procedure _streamControllerSetOnResume; + final List<_AsyncStarFrame> _asyncStarFrames = []; bool _enclosingIsAsyncStar = false; - late final controllerNullableObjectType = InterfaceType( - coreTypes.index.getClass('dart:async', 'StreamController'), - Nullability.nonNullable, - [coreTypes.objectNullableRawType]); - late final completerBoolType = InterfaceType( - coreTypes.index.getClass('dart:async', 'Completer'), - Nullability.nonNullable, - [coreTypes.boolNonNullableRawType]); final ListFactorySpecializer _listFactorySpecializer; @@ -58,9 +70,40 @@ class _WasmTransformer extends Transformer { _nonNullableTypeType = coreTypes.index .getClass('dart:core', '_Type') .getThisType(coreTypes, Nullability.nonNullable), - _wasmBaseClass = coreTypes.index.getClass('dart:_wasm', '_WasmBase'), - _wasmArrayClass = coreTypes.index.getClass('dart:_wasm', 'WasmArray'), _coreLibrary = coreTypes.index.getLibrary('dart:core'), + _completerClass = coreTypes.index.getClass('dart:async', 'Completer'), + _streamControllerClass = + coreTypes.index.getClass('dart:async', 'StreamController'), + _wasmArrayClass = coreTypes.index.getClass('dart:_wasm', 'WasmArray'), + _wasmBaseClass = coreTypes.index.getClass('dart:_wasm', '_WasmBase'), + _completerComplete = + coreTypes.index.getProcedure('dart:async', 'Completer', 'complete'), + _completerConstructor = + coreTypes.index.getProcedure('dart:async', 'Completer', ''), + _completerGetFuture = coreTypes.index + .getProcedure('dart:async', 'Completer', 'get:future'), + _streamControllerAdd = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'add'), + _streamControllerAddError = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'addError'), + _streamControllerAddStream = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'addStream'), + _streamControllerClose = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'close'), + _streamControllerConstructor = + coreTypes.index.getProcedure('dart:async', 'StreamController', ''), + _streamControllerGetHasListener = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'get:hasListener'), + _streamControllerGetIsPaused = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'get:isPaused'), + _streamControllerGetStream = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'get:stream'), + _streamControllerSetOnCancel = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'set:onCancel'), + _streamControllerSetOnListen = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'set:onListen'), + _streamControllerSetOnResume = coreTypes.index + .getProcedure('dart:async', 'StreamController', 'set:onResume'), _listFactorySpecializer = ListFactorySpecializer(coreTypes); @override @@ -279,353 +322,257 @@ class _WasmTransformer extends Transformer { return _lowerForIn(stmt); } - StaticInvocation _completerBoolInitializer() => StaticInvocation( - coreTypes.index.getProcedure('dart:async', 'Completer', ''), - Arguments([], types: [coreTypes.boolNonNullableRawType])); - InstanceInvocation _addToController( VariableDeclaration controller, Expression expression, int fileOffset) { - Procedure controllerAdd = - coreTypes.index.getProcedure('dart:async', 'StreamController', 'add'); + final controllerNullableObjectType = InterfaceType(_streamControllerClass, + Nullability.nonNullable, [coreTypes.objectNullableRawType]); FunctionType controllerAddType = Substitution.fromInterfaceType(controllerNullableObjectType) - .substituteType(controllerAdd.function + .substituteType(_streamControllerAdd.function .computeThisFunctionType(Nullability.nonNullable)) as FunctionType; return InstanceInvocation(InstanceAccessKind.Instance, VariableGet(controller), Name('add'), Arguments([expression]), - interfaceTarget: controllerAdd, functionType: controllerAddType) + interfaceTarget: _streamControllerAdd, functionType: controllerAddType) ..fileOffset = fileOffset; } - InstanceInvocation _addCompleterToController(VariableDeclaration controller, - VariableDeclaration completer, int fileOffset) => - _addToController(controller, VariableGet(completer), fileOffset); - - AwaitExpression _awaitCompleterFuture( - VariableDeclaration completer, int fileOffset) { - Procedure completerFuture = - coreTypes.index.getProcedure('dart:async', 'Completer', 'get:future'); - // Future - DartType completerFutureType = InterfaceType(coreTypes.futureClass, - Nullability.nonNullable, [coreTypes.boolNonNullableRawType]); - return AwaitExpression(InstanceGet( - InstanceAccessKind.Instance, VariableGet(completer), Name('future'), - interfaceTarget: completerFuture, resultType: completerFutureType) - ..fileOffset = fileOffset); - } - TreeNode _lowerAsyncStar(FunctionNode functionNode) { - // TODO(joshualitt): This lowering is mostly reasonable, but if possible we - // should try and figure out a way to remove the even / odd dance. That - // said, this will be replaced by an intrinsic implementation ASAP so it may - // not be worth spending anymore time on this(aside from bug fixes). + // Convert the function into: // - // Transform + // Stream name(args) { + // var #controller = StreamController(sync: true); + // + // void #body() async { + // Completer? #paused; + // + // #controller.onResume = #controller.onCancel = () { + // #paused?.complete(null); + // #paused = null; + // }; + // + // try { + // + // } catch (e, s) { + // #controller.addError(e, s); + // } finally { + // #controller.close(); + // } + // } + // + // #controller.onListen = () { + // scheduleMicrotask(#body); + // }; + // + // return controller.stream; + // } + // + // Where `` is the body of `functionNode` with these + // transformations: // - // Stream foo() async* { - // ... - // yield i; - // ... - // yield* bar; - // ... + // - yield* e + // + // ==> + // + // await #controller.addStream(e); + // if (!#controller.hasListener) { + // return; // } // - // Into + // - yield e // - // Stream foo() { - // StreamController #controller = StreamController(); - // Future Function() #body = () async { - // Completer #completer = Completer(); - // #controller.add(#completer); - // try { - // await #completer.future; - // ... - // #controller.add(i); - // #completer = Completer(); - // #controller.add(#completer) - // await #completer.future; - // ... - // await for (var i in bar) { - // #controller.add(i); - // #completer = Completer(); - // #controller.add(#completer) - // await #completer.future; - // } - // ... - // } catch (e) { - // #controller.addError(e); - // } finally { - // #controller.close(); - // } - // }; - // bool isEven = false; - // bool isFirst = true; - // #controller.add(null); - // return #controller.stream.asyncMap((value) async { - // if (isFirst) { - // #body(); - // return null; - // } - // if (value is Completer) { - // value.complete(true); - // } - // return value; - // }).where((value) { - // if (isFirst) { - // isFirst = false; - // return false; - // } - // bool keep = isEven; - // isEven = !isEven; - // return keep; - // }).cast(); + // ==> + // + // #controller.add(e); + // if (#controller.isPaused) { + // await (#paused = Completer()).future; + // } + // if (!#controller.hasListener) { + // return; // } - int fileOffset = functionNode.fileOffset; + // + // The `yield` and `yield*` transformations are done by [visitYieldStatement]. - // Initialize `#controller`. + final fileOffset = functionNode.fileOffset; + final emittedValueType = functionNode.emittedValueType!; + + // var #controller = StreamController(sync: true); + final controllerObjectType = InterfaceType( + _streamControllerClass, Nullability.nonNullable, [emittedValueType]); + + // StreamController(sync: true) final controllerInitializer = StaticInvocation( - coreTypes.index.getProcedure('dart:async', 'StreamController', ''), - Arguments([], types: [coreTypes.objectNullableRawType])); - final controller = VariableDeclaration('#controller', + _streamControllerConstructor, + Arguments([], types: [ + emittedValueType + ], named: [ + NamedExpression('sync', ConstantExpression(BoolConstant(true))) + ])); + + // var #controller = ... + final controllerVar = VariableDeclaration('#controller', initializer: controllerInitializer..fileOffset = fileOffset, - type: controllerNullableObjectType, + type: controllerObjectType, isSynthesized: true) ..fileOffset = fileOffset; - // Initialize `#completer`. - final completer = VariableDeclaration('#completer', - initializer: _completerBoolInitializer()..fileOffset = fileOffset, - type: completerBoolType, - isSynthesized: true) - ..fileOffset = fileOffset; + // `void #body() async { ... }` statements. + final List bodyStatements = []; - // Close `#controller`. - Procedure controllerCloseProc = - coreTypes.index.getProcedure('dart:async', 'StreamController', 'close'); - FunctionType controllerCloseType = - Substitution.fromInterfaceType(controllerNullableObjectType) - .substituteType(controllerCloseProc.function - .computeThisFunctionType(Nullability.nonNullable)) - as FunctionType; - final callControllerClose = InstanceInvocation(InstanceAccessKind.Instance, - VariableGet(controller), Name('close'), Arguments([]), - interfaceTarget: controllerCloseProc, - functionType: controllerCloseType); - - // Create a frame so yield statements within the body can access the right - // controller / completer. - _asyncStarFrames.add(_AsyncStarFrame(controller, completer)); - - // Visit the body to transform any yields. We will re-visit after - // transformation just to ensure everything we've added will also be - // lowered. - Statement? transformedBody = - functionNode.body?.accept(this) as Statement?; + // Completer? #paused; + final pausedVarType = InterfaceType( + _completerClass, Nullability.nullable, [const VoidType()]); + + final pausedVar = VariableDeclaration('#paused', + initializer: null, type: pausedVarType, isSynthesized: true); + + bodyStatements.add(pausedVar); + + // controller.onResume = controller.onCancel = () { + // #paused?.complete(null); + // #paused = null; + // }; + final List onCancelCallbackBodyStatements = [ + IfStatement( + EqualsNull(VariableGet(pausedVar)), + Block([]), + Block([ + ExpressionStatement(InstanceInvocation( + InstanceAccessKind.Instance, + VariableGet(pausedVar), + Name('complete'), + Arguments([ConstantExpression(NullConstant())]), + interfaceTarget: _completerComplete, + functionType: substitute(_completerComplete.getterType, { + _completerClass.typeParameters.first: const VoidType() + }) as FunctionType, + )), + ExpressionStatement(VariableSet( + pausedVar, + ConstantExpression(NullConstant()), + )) + ])), + ]; + + final onCancelCallback = FunctionExpression(FunctionNode( + Block(onCancelCallbackBodyStatements), + typeParameters: [], + positionalParameters: [], + namedParameters: [], + requiredParameterCount: 0, + returnType: const VoidType(), + )); + + final onCancelCallbackVar = + VariableDeclaration("#onCancelCallback", initializer: onCancelCallback); + + bodyStatements.add(onCancelCallbackVar); + + bodyStatements.add(ExpressionStatement(InstanceSet( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name('onResume'), + VariableGet(onCancelCallbackVar), + interfaceTarget: _streamControllerSetOnResume))); + + bodyStatements.add(ExpressionStatement(InstanceSet( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name('onCancel'), + VariableGet(onCancelCallbackVar), + interfaceTarget: _streamControllerSetOnCancel))); + + _asyncStarFrames + .add(_AsyncStarFrame(controllerVar, pausedVar, emittedValueType)); + final Statement transformedBody = + functionNode.body!.accept(this) as Statement; _asyncStarFrames.removeLast(); - // Try-catch-finally around the body to call `controller.addError` and - // `controller.close`. + // The body will be wrapped with a `try-catch` to pass the error to the + // controller, and `try-finally` to close the controller. final exceptionVar = VariableDeclaration(null, isSynthesized: true); + final stackTraceVar = VariableDeclaration(null, isSynthesized: true, type: coreTypes.stackTraceRawType(Nullability.nonNullable)); - final Procedure controllerAddErrorProc = coreTypes.index - .getProcedure('dart:async', 'StreamController', 'addError'); - final FunctionType controllerAddErrorType = - Substitution.fromInterfaceType(controllerNullableObjectType) - .substituteType(controllerAddErrorProc.function - .computeThisFunctionType(Nullability.nonNullable)) - as FunctionType; - final tryCatch = TryCatch( - Block([ - ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)), - if (transformedBody != null) transformedBody, - ]), - [ - Catch( - exceptionVar, - stackTrace: stackTraceVar, - ExpressionStatement(InstanceInvocation( - InstanceAccessKind.Instance, - VariableGet(controller), - Name('addError'), - Arguments([VariableGet(exceptionVar), VariableGet(stackTraceVar)]), - interfaceTarget: controllerAddErrorProc, - functionType: controllerAddErrorType, - )), - ) - ], - ); - final tryFinally = - TryFinally(tryCatch, ExpressionStatement(callControllerClose)); - - // Locally declare body function. - final bodyFunction = FunctionNode( - Block([ - completer, - ExpressionStatement( - _addCompleterToController(controller, completer, fileOffset)), - tryFinally, - ]), + + final catch_ = Catch( + exceptionVar, + stackTrace: stackTraceVar, + ExpressionStatement(InstanceInvocation( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name("addError"), + Arguments([VariableGet(exceptionVar), VariableGet(stackTraceVar)]), + interfaceTarget: _streamControllerAddError, + functionType: _streamControllerAddError.getterType as FunctionType, + ))); + + final finalizer = ExpressionStatement(InstanceInvocation( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name("close"), + Arguments([]), + interfaceTarget: _streamControllerClose, + functionType: _streamControllerClose.getterType as FunctionType, + )); + + bodyStatements + .add(TryFinally(TryCatch(transformedBody, [catch_]), finalizer)); + + final bodyFunction = FunctionNode(Block(bodyStatements), emittedValueType: const VoidType(), returnType: InterfaceType( coreTypes.futureClass, Nullability.nonNullable, [const VoidType()]), asyncMarker: AsyncMarker.Async, dartAsyncMarker: AsyncMarker.Async); + final bodyInitializer = FunctionExpression(bodyFunction); - FunctionType bodyFunctionType = + + final bodyFunctionType = bodyFunction.computeThisFunctionType(Nullability.nonNullable); - final body = VariableDeclaration('#body', + + final bodyVar = VariableDeclaration('#body', initializer: bodyInitializer..fileOffset = fileOffset, type: bodyFunctionType, isSynthesized: true) ..fileOffset = fileOffset; - // Invoke body. - final invokeBody = FunctionInvocation( - FunctionAccessKind.FunctionType, VariableGet(body), Arguments([]), - functionType: bodyFunctionType); + // controller.onListen = () { + // scheduleMicrotask(_body); + // }; + final scheduleMicrotaskProcedure = + coreTypes.index.getTopLevelProcedure('dart:async', 'scheduleMicrotask'); - // Create a 'counting' sentinel to let us know which values to filter. - final isEven = VariableDeclaration('#isEven', - initializer: ConstantExpression(BoolConstant(false)) - ..fileOffset = fileOffset, - type: coreTypes.boolNonNullableRawType, - isSynthesized: true) - ..fileOffset = fileOffset; - final isFirst = VariableDeclaration('#isFirst', - initializer: ConstantExpression(BoolConstant(true)) - ..fileOffset = fileOffset, - type: coreTypes.boolNonNullableRawType, - isSynthesized: true) - ..fileOffset = fileOffset; - - // Get `controller.stream` - Procedure controllerStream = coreTypes.index - .getProcedure('dart:async', 'StreamController', 'get:stream'); - DartType controllerStreamType = - Substitution.fromInterfaceType(controllerNullableObjectType) - .substituteType(controllerStream.function.returnType); - final getControllerStream = InstanceGet( - InstanceAccessKind.Instance, VariableGet(controller), Name('stream'), - interfaceTarget: controllerStream, resultType: controllerStreamType); - - // Prepare `completerPrePass` to issue a round of completions to our hidden - // completers. - Procedure completerComplete = - coreTypes.index.getProcedure('dart:async', 'Completer', 'complete'); - FunctionType completerCompleteType = - Substitution.fromInterfaceType(completerBoolType).substituteType( - completerComplete.function - .computeThisFunctionType(Nullability.nonNullable)) - as FunctionType; - final completerPrePassArg = VariableDeclaration('value', - type: coreTypes.objectNullableRawType, isSynthesized: true); - final completerPrePass = FunctionExpression(FunctionNode( - Block([ - IfStatement( - VariableGet(isFirst), - Block([ - ExpressionStatement(invokeBody), - ReturnStatement(ConstantExpression(NullConstant())), - ]), - null), - IfStatement( - Not(VariableGet(isEven)), - ExpressionStatement(InstanceInvocation( - InstanceAccessKind.Instance, - VariableGet(completerPrePassArg), - Name('complete'), - Arguments([ConstantExpression(BoolConstant(true))]), - interfaceTarget: completerComplete, - functionType: completerCompleteType)), - null), - ReturnStatement(VariableGet(completerPrePassArg)), - ]), - positionalParameters: [completerPrePassArg], - returnType: FutureOrType( - coreTypes.objectNullableRawType, Nullability.nonNullable), - asyncMarker: AsyncMarker.Async, - dartAsyncMarker: AsyncMarker.Async, - emittedValueType: coreTypes.objectNullableRawType, - )); - - // Call `asyncMap`. - Procedure asyncMap = - coreTypes.index.getProcedure('dart:async', 'Stream', 'asyncMap'); - final streamType = InterfaceType(coreTypes.streamClass, - Nullability.nonNullable, [coreTypes.objectNullableRawType]); - final asyncMapType = FunctionType([ - FunctionType([ - coreTypes.objectNullableRawType - ], FutureOrType(coreTypes.objectNullableRawType, Nullability.nonNullable), - Nullability.nonNullable, requiredParameterCount: 1) - ], streamType, Nullability.nonNullable, requiredParameterCount: 1); - final callAsyncMap = InstanceInvocation( + final setControllerOnListen = InstanceSet( InstanceAccessKind.Instance, - getControllerStream, - Name('asyncMap'), - Arguments([completerPrePass], types: [coreTypes.objectNullableRawType]), - interfaceTarget: asyncMap, - functionType: asyncMapType); - - // Call `where`. - final whereFilterArg = VariableDeclaration('value', - type: coreTypes.objectNullableRawType, isSynthesized: true); - final whereKeep = VariableDeclaration('keep', - initializer: VariableGet(isEven), - type: coreTypes.boolNonNullableRawType, - isSynthesized: true); + VariableGet(controllerVar), + Name('onListen'), + FunctionExpression(FunctionNode(ExpressionStatement(StaticInvocation( + scheduleMicrotaskProcedure, Arguments([VariableGet(bodyVar)]))))), + interfaceTarget: _streamControllerSetOnListen); - final whereFilter = FunctionExpression(FunctionNode( - Block([ - IfStatement( - VariableGet(isFirst), - Block([ - ExpressionStatement(VariableSet( - isFirst, ConstantExpression(BoolConstant(false)))), - ReturnStatement(ConstantExpression(BoolConstant(false))) - ]), - null), - whereKeep, - ExpressionStatement(VariableSet(isEven, Not(VariableGet(isEven)))), - ReturnStatement(VariableGet(whereKeep)), - ]), - positionalParameters: [whereFilterArg], - returnType: coreTypes.boolNonNullableRawType)); - - Procedure whereProc = - coreTypes.index.getProcedure('dart:async', 'Stream', 'where'); - FunctionType whereProcType = Substitution.fromInterfaceType(streamType) - .substituteType(whereProc.function - .computeThisFunctionType(Nullability.nonNullable)) as FunctionType; - final callWhere = InstanceInvocation(InstanceAccessKind.Instance, - callAsyncMap, Name('where'), Arguments([whereFilter]), - interfaceTarget: whereProc, functionType: whereProcType); - - // Finally call cast. - - final DartType streamTypeArgument = functionNode.emittedValueType!; - Procedure castProc = - coreTypes.index.getProcedure('dart:async', 'Stream', 'cast'); - final returnStreamType = InterfaceType(coreTypes.streamClass, - streamTypeArgument.nullability, [streamTypeArgument]); - final castProcType = FunctionType( - [], returnStreamType, Nullability.nonNullable, - requiredParameterCount: 1); - final castToExpectedType = InstanceInvocation(InstanceAccessKind.Instance, - callWhere, Name('cast'), Arguments([], types: [streamTypeArgument]), - interfaceTarget: castProc, functionType: castProcType); return FunctionNode( Block([ - controller, - body, - isFirst, - isEven, - ExpressionStatement(_addToController( - controller, ConstantExpression(NullConstant()), fileOffset)), - ReturnStatement(castToExpectedType), + // var controller = StreamController(sync: true); + controllerVar, + + // var #body = ...; + bodyVar, + + // controller.onListen = ...; + ExpressionStatement(setControllerOnListen), + + // return controller.stream; + ReturnStatement(InstanceGet( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name("stream"), + interfaceTarget: _streamControllerGetStream, + resultType: substitute(_streamControllerGetStream.getterType, { + _streamControllerClass.typeParameters.first: emittedValueType, + }), + )) ]), typeParameters: functionNode.typeParameters, positionalParameters: functionNode.positionalParameters, @@ -642,48 +589,92 @@ class _WasmTransformer extends Transformer { if (!_enclosingIsAsyncStar) { return super.visitYieldStatement(yield); } - int fileOffset = yield.fileOffset; - _AsyncStarFrame frame = _asyncStarFrames.last; - VariableDeclaration controller = frame.controller; - VariableDeclaration completer = frame.completer; - bool isYieldStar = yield.isYieldStar; - - // If [isYieldStar] then we need to create an `await for` loop to wrap the - // yields. - DartType yieldExpressionType = yield.expression.getStaticType(typeContext); - VariableDeclaration? awaitForVar; - if (isYieldStar) { - DartType awaitVarType = const DynamicType(); - if (yieldExpressionType is InterfaceType) { - Class cls = yieldExpressionType.classReference.asClass; - if (cls == coreTypes.streamClass) { - awaitVarType = yieldExpressionType.typeArguments.single; - } - } - awaitForVar = VariableDeclaration('#awaitForVar', - type: awaitVarType, isSynthesized: true) - ..fileOffset = fileOffset; - } - final yieldBody = Block([ - ExpressionStatement(_addToController( - controller, - isYieldStar ? VariableGet(awaitForVar!) : yield.expression, - fileOffset)), - ExpressionStatement(VariableSet(completer, _completerBoolInitializer())), - ExpressionStatement( - _addCompleterToController(controller, completer, fileOffset)), - ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)), - ]); + final fileOffset = yield.fileOffset; + final frame = _asyncStarFrames.last; + final controllerVar = frame.controllerVar; + final pausedVar = frame.pausedVar; + final isYieldStar = yield.isYieldStar; + + final transformedExpression = yield.expression.accept(this) as Expression; + + final List statements = []; + if (isYieldStar) { - // If this is a yield* then wrap the yield in an `await for`. - ForInStatement awaitForIn = ForInStatement( - awaitForVar!, yield.expression, yieldBody, - isAsync: true); - return awaitForIn.accept(this); + // yield* e + // + // ==> + // + // await #controller.addStream(e); + // if (!#controller.hasListener) return; + + final controllerAddStreamProcedureType = + _streamControllerAddStream.getterType as FunctionType; + + statements.add(ExpressionStatement(AwaitExpression(InstanceInvocation( + InstanceAccessKind.Instance, + VariableGet(controllerVar), + Name('addStream'), + Arguments([transformedExpression]), + interfaceTarget: _streamControllerAddStream, + functionType: substitute(controllerAddStreamProcedureType, { + _streamControllerClass.typeParameters.first: frame.emittedValueType, + }) as FunctionType, + )))); + + statements.add(IfStatement( + InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar), + Name('hasListener'), + interfaceTarget: _streamControllerGetHasListener, + resultType: coreTypes.boolNonNullableRawType), + Block([]), + ReturnStatement())); } else { - return yieldBody.accept(this); + // yield e + // + // ==> + // + // #controller.add(e); + // if (#controller.isPaused) { + // await (#paused = Completer()).future; + // } + // if (!#controller.hasListener) { + // return; + // } + + statements.add(ExpressionStatement( + _addToController(controllerVar, yield.expression, fileOffset))); + + // if (controller.isPaused) ... + statements.add(IfStatement( + InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar), + Name('isPaused'), + interfaceTarget: _streamControllerGetIsPaused, + resultType: coreTypes.boolNonNullableRawType), + ExpressionStatement(AwaitExpression(InstanceGet( + InstanceAccessKind.Instance, + VariableSet( + pausedVar, + StaticInvocation(_completerConstructor, + Arguments([], types: [const VoidType()]))), + Name('future'), + interfaceTarget: _completerGetFuture, + resultType: substitute(_completerGetFuture.getterType, + {_completerClass.typeParameters.first: const VoidType()})))), + null)); + + // if (!controller.hasListener) return; + statements.add(IfStatement( + InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar), + Name('hasListener'), + interfaceTarget: _streamControllerGetHasListener, + resultType: coreTypes.boolNonNullableRawType), + Block([]), + ReturnStatement(), + )); } + + return Block(statements); } @override @@ -715,8 +706,9 @@ class _WasmTransformer extends Transformer { } class _AsyncStarFrame { - final VariableDeclaration controller; - final VariableDeclaration completer; + final VariableDeclaration controllerVar; + final VariableDeclaration pausedVar; + final DartType emittedValueType; - _AsyncStarFrame(this.controller, this.completer); + _AsyncStarFrame(this.controllerVar, this.pausedVar, this.emittedValueType); } diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart index 203c033cd9ab..c1ee83921f79 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart @@ -18,6 +18,7 @@ import '../../builder/prefix_builder.dart'; import '../../scope.dart'; import '../../source/diet_parser.dart'; import '../../source/source_library_builder.dart'; +import '../../uri_offset.dart'; import 'macro.dart'; List? prebuildAnnotations( @@ -211,15 +212,14 @@ class _MacroListener implements Listener { constructorName, new macro.Arguments(argumentsNode.positionalArguments, argumentsNode.namedArguments), - fileUri: uri, - fileOffset: beginToken.next!.charOffset))); + uriOffset: new UriOffset(uri, beginToken.next!.charOffset)))); return; } } else { if (_macroClassBuilder != null && _unhandledReason != null) { _erroneousMacroApplication = new MacroApplication.error( _unhandledReason!, _macroClassBuilder!, - fileUri: uri, fileOffset: beginToken.next!.charOffset); + uriOffset: new UriOffset(uri, beginToken.next!.charOffset)); } } pushUnsupported(); diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart b/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart index 2b01d0a4a9e3..acedc218ae02 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart @@ -23,6 +23,7 @@ import '../../source/source_factory_builder.dart'; import '../../source/source_field_builder.dart'; import '../../source/source_loader.dart'; import '../../source/source_procedure_builder.dart'; +import '../../uri_offset.dart'; import '../hierarchy/hierarchy_builder.dart'; import 'identifiers.dart'; import 'types.dart'; @@ -41,8 +42,9 @@ class MacroIntrospection { Map _typeParameters = {}; Map _typeAliasDeclarations = {}; - Map _memberDeclarations = {}; + Map _memberDeclarations = {}; Map _libraries = {}; + Map _declarationOffsets = {}; MacroIntrospection(this._sourceLoader) : types = new MacroTypes(_sourceLoader); @@ -64,30 +66,46 @@ class MacroIntrospection { } void clear() { + _libraries.clear(); + _classDeclarations.clear(); + _classBuilders.clear(); + _memberDeclarations.clear(); + _typeAliasDeclarations.clear(); + _declarationOffsets.clear(); types.clear(); } + /// Returns the [UriOffset] associated with [declaration]. + UriOffset getLocationFromDeclaration(macro.Declaration declaration) => + _declarationOffsets[declaration]!; + + /// Returns the [macro.Declaration] corresponding to [memberBuilder]. macro.Declaration getMemberDeclaration(MemberBuilder memberBuilder) { memberBuilder = memberBuilder.origin as MemberBuilder; return _memberDeclarations[memberBuilder] ??= _createMemberDeclaration(memberBuilder); } + /// Returns the [macro.ParameterizedTypeDeclaration] corresponding to + /// [builder]. macro.ParameterizedTypeDeclaration getClassDeclaration(ClassBuilder builder) { builder = builder.origin; return _classDeclarations[builder] ??= _createClassDeclaration(builder); } + /// Returns the [macro.TypeAliasDeclaration] corresponding to [builder]. macro.TypeAliasDeclaration getTypeAliasDeclaration(TypeAliasBuilder builder) { return _typeAliasDeclarations[builder] ??= _createTypeAliasDeclaration(builder); } + /// Returns the [ClassBuilder] corresponding to [declaration]. ClassBuilder _getClassBuilder( macro.ParameterizedTypeDeclaration declaration) { return _classBuilders[declaration]!; } + /// Creates the [macro.Declaration] corresponding to [memberBuilder]. macro.Declaration _createMemberDeclaration(MemberBuilder memberBuilder) { if (memberBuilder is SourceProcedureBuilder) { return _createFunctionDeclaration(memberBuilder); @@ -104,6 +122,8 @@ class MacroIntrospection { } } + /// Resolves [identifier] to the [macro.TypeDeclaration] that it corresponds + /// to. macro.TypeDeclaration resolveDeclaration(macro.Identifier identifier) { if (identifier is MemberBuilderIdentifier) { return getClassDeclaration(identifier.memberBuilder.classBuilder!); @@ -131,6 +151,8 @@ class MacroIntrospection { } } + /// Resolves [identifier] to the [macro.ResolvedIdentifier] that it + /// corresponds to. macro.ResolvedIdentifier resolveIdentifier(macro.Identifier identifier) { if (identifier is IdentifierImpl) { return identifier.resolveIdentifier(); @@ -140,19 +162,25 @@ class MacroIntrospection { } } + /// Returns the [macro.LibraryImpl] corresponding to [builder]. macro.LibraryImpl getLibrary(LibraryBuilder builder) { - return _libraries[builder] ??= () { - final Version version = builder.library.languageVersion; - return new macro.LibraryImpl( - id: macro.RemoteInstance.uniqueId, - uri: builder.importUri, - languageVersion: - new macro.LanguageVersionImpl(version.major, version.minor), - // TODO: Provide metadata annotations. - metadata: const []); - }(); + return _libraries[builder] ??= _createLibraryImpl(builder); } + /// Creates the [macro.LibraryImpl] corresponding to [builder]. + macro.LibraryImpl _createLibraryImpl(LibraryBuilder builder) { + final Version version = builder.library.languageVersion; + return new macro.LibraryImpl( + id: macro.RemoteInstance.uniqueId, + uri: builder.importUri, + languageVersion: + new macro.LanguageVersionImpl(version.major, version.minor), + // TODO(johnniwinther): Provide metadata annotations. + metadata: const []); + } + + /// Creates the [macro.ParameterizedTypeDeclaration] corresponding to + /// [builder]. macro.ParameterizedTypeDeclaration _createClassDeclaration( ClassBuilder builder) { assert( @@ -184,7 +212,7 @@ class MacroIntrospection { _nominalVariableBuildersToDeclarations( builder.libraryBuilder, builder.typeVariables); final List interfaces = - types.typeBuildersToAnnotations( + types.getNamedTypeAnnotations( builder.libraryBuilder, builder.interfaceBuilders); final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); @@ -198,7 +226,7 @@ class MacroIntrospection { typeParameters: typeParameters, hasBase: builder.isBase, interfaces: interfaces, - superclassConstraints: types.typeBuildersToAnnotations( + superclassConstraints: types.getNamedTypeAnnotations( builder.libraryBuilder, builder.onTypes)) // This cast is not necessary but LUB doesn't give the desired type // without it. @@ -219,16 +247,19 @@ class MacroIntrospection { hasMixin: builder.isMixinClass, hasSealed: builder.isSealed, mixins: - types.typeBuildersToAnnotations(builder.libraryBuilder, mixins), + types.getNamedTypeAnnotations(builder.libraryBuilder, mixins), superclass: supertypeBuilder != null - ? types.computeTypeAnnotation( + ? types.getTypeAnnotation( builder.libraryBuilder, supertypeBuilder) as macro.NamedTypeAnnotationImpl : null); _classBuilders[declaration] = builder; + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.charOffset); return declaration; } + /// Creates the [macro.TypeAliasDeclaration] corresponding to [builder]. macro.TypeAliasDeclaration _createTypeAliasDeclaration( TypeAliasBuilder builder) { final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); @@ -247,30 +278,36 @@ class MacroIntrospection { metadata: const [], typeParameters: typeParameters, aliasedType: - types.computeTypeAnnotation(builder.libraryBuilder, builder.type)); + types.getTypeAnnotation(builder.libraryBuilder, builder.type)); + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.charOffset); return declaration; } - List> _createParameters( - MemberBuilder builder, List? formals) { - List? positionalParameters; - List? namedParameters; + /// Creates the positional and named [macro.FormalParameterDeclarationImpl]s + /// for [formals]. + ( + List, + List + ) _createParameters( + LibraryBuilder libraryBuilder, List? formals) { if (formals == null) { - positionalParameters = namedParameters = const []; + return const ([], []); } else { - positionalParameters = []; - namedParameters = []; - final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); + List positionalParameters = []; + List namedParameters = []; + final macro.LibraryImpl library = getLibrary(libraryBuilder); for (FormalParameterBuilder formal in formals) { macro.TypeAnnotationImpl type = - types.computeTypeAnnotation(builder.libraryBuilder, formal.type); + types.getTypeAnnotation(libraryBuilder, formal.type); macro.IdentifierImpl identifier = new FormalParameterBuilderIdentifier( id: macro.RemoteInstance.uniqueId, name: formal.name, parameterBuilder: formal, - libraryBuilder: builder.libraryBuilder); + libraryBuilder: libraryBuilder); if (formal.isNamed) { - namedParameters.add(new macro.FormalParameterDeclarationImpl( + macro.FormalParameterDeclarationImpl declaration = + new macro.FormalParameterDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: identifier, library: library, @@ -279,9 +316,13 @@ class MacroIntrospection { isRequired: formal.isRequiredNamed, isNamed: true, type: type, - )); + ); + namedParameters.add(declaration); + _declarationOffsets[declaration] = + new UriOffset(formal.fileUri, formal.charOffset); } else { - positionalParameters.add(new macro.FormalParameterDeclarationImpl( + macro.FormalParameterDeclarationImpl declaration = + new macro.FormalParameterDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: identifier, library: library, @@ -290,13 +331,17 @@ class MacroIntrospection { isRequired: formal.isRequiredPositional, isNamed: false, type: type, - )); + ); + positionalParameters.add(declaration); + _declarationOffsets[declaration] = + new UriOffset(formal.fileUri, formal.charOffset); } } + return (positionalParameters, namedParameters); } - return [positionalParameters, namedParameters]; } + /// Creates the [macro.ConstructorDeclaration] corresponding to [builder]. macro.ConstructorDeclaration _createConstructorDeclaration( SourceConstructorBuilder builder) { List? formals = null; @@ -304,11 +349,14 @@ class MacroIntrospection { if (builder is DeclaredSourceConstructorBuilder) { formals = builder.formals; } - List> parameters = - _createParameters(builder, formals); + var ( + List positionalParameters, + List namedParameters + ) = _createParameters(builder.libraryBuilder, formals); macro.ParameterizedTypeDeclaration definingClass = getClassDeclaration(builder.classBuilder!); - return new macro.ConstructorDeclarationImpl( + macro.ConstructorDeclaration declaration = + new macro.ConstructorDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, @@ -322,24 +370,33 @@ class MacroIntrospection { // TODO(johnniwinther): Real implementation of hasBody. hasBody: true, hasExternal: builder.isExternal, - positionalParameters: parameters[0], - namedParameters: parameters[1], + positionalParameters: positionalParameters, + namedParameters: namedParameters, // TODO(johnniwinther): Support constructor return type. - returnType: types.computeTypeAnnotation(builder.libraryBuilder, null), + returnType: types.getTypeAnnotation(builder.libraryBuilder, null), // TODO(johnniwinther): Support typeParameters typeParameters: const [], ); + if (builder.fileUri != null) { + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri!, builder.charOffset); + } + return declaration; } + /// Creates the [macro.ConstructorDeclaration] corresponding to [builder]. macro.ConstructorDeclaration _createFactoryDeclaration( SourceFactoryBuilder builder) { - List> parameters = - _createParameters(builder, builder.formals); + var ( + List positionalParameters, + List namedParameters + ) = _createParameters(builder.libraryBuilder, builder.formals); macro.ParameterizedTypeDeclaration definingClass = // TODO(johnniwinther): Support extension type factories. getClassDeclaration(builder.classBuilder!); - return new macro.ConstructorDeclarationImpl( + macro.ConstructorDeclaration declaration = + new macro.ConstructorDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, @@ -353,36 +410,43 @@ class MacroIntrospection { // TODO(johnniwinther): Real implementation of hasBody. hasBody: true, hasExternal: builder.isExternal, - positionalParameters: parameters[0], - namedParameters: parameters[1], + positionalParameters: positionalParameters, + namedParameters: namedParameters, // TODO(johnniwinther): Support constructor return type. - returnType: types.computeTypeAnnotation(builder.libraryBuilder, null), + returnType: types.getTypeAnnotation(builder.libraryBuilder, null), // TODO(johnniwinther): Support typeParameters typeParameters: const [], ); + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.charOffset); + return declaration; } + /// Creates the [macro.FunctionDeclaration] corresponding to [builder]. macro.FunctionDeclaration _createFunctionDeclaration( SourceProcedureBuilder builder) { - List> parameters = - _createParameters(builder, builder.formals); + var ( + List positionalParameters, + List namedParameters + ) = _createParameters(builder.libraryBuilder, builder.formals); macro.ParameterizedTypeDeclaration? definingClass = null; if (builder.classBuilder != null) { definingClass = getClassDeclaration(builder.classBuilder!); } final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); + macro.FunctionDeclaration declaration; if (definingClass != null) { // TODO(johnniwinther): Should static fields be field or variable // declarations? - return new macro.MethodDeclarationImpl( + declaration = new macro.MethodDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, id: macro.RemoteInstance.uniqueId, name: builder.name), library: library, - // TODO: Provide metadata annotations. + // TODO(johnniwinther): Provide metadata annotations. metadata: const [], definingType: definingClass.identifier as macro.IdentifierImpl, // TODO(johnniwinther): Real implementation of hasBody. @@ -392,14 +456,14 @@ class MacroIntrospection { isOperator: builder.isOperator, isSetter: builder.isSetter, hasStatic: builder.isStatic, - positionalParameters: parameters[0], - namedParameters: parameters[1], - returnType: types.computeTypeAnnotation( + positionalParameters: positionalParameters, + namedParameters: namedParameters, + returnType: types.getTypeAnnotation( builder.libraryBuilder, builder.returnType), // TODO(johnniwinther): Support typeParameters typeParameters: const []); } else { - return new macro.FunctionDeclarationImpl( + declaration = new macro.FunctionDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, @@ -414,15 +478,19 @@ class MacroIntrospection { isGetter: builder.isGetter, isOperator: builder.isOperator, isSetter: builder.isSetter, - positionalParameters: parameters[0], - namedParameters: parameters[1], - returnType: types.computeTypeAnnotation( + positionalParameters: positionalParameters, + namedParameters: namedParameters, + returnType: types.getTypeAnnotation( builder.libraryBuilder, builder.returnType), // TODO(johnniwinther): Support typeParameters typeParameters: const []); } + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.charOffset); + return declaration; } + /// Creates the [macro.VariableDeclaration] corresponding to [builder]. macro.VariableDeclaration _createVariableDeclaration( SourceFieldBuilder builder) { macro.ParameterizedTypeDeclaration? definingClass = null; @@ -430,10 +498,11 @@ class MacroIntrospection { definingClass = getClassDeclaration(builder.classBuilder!); } final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); + macro.VariableDeclaration declaration; if (definingClass != null) { // TODO(johnniwinther): Should static fields be field or variable // declarations? - return new macro.FieldDeclarationImpl( + declaration = new macro.FieldDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, @@ -450,10 +519,9 @@ class MacroIntrospection { hasInitializer: builder.hasInitializer, hasLate: builder.isLate, hasStatic: builder.isStatic, - type: types.computeTypeAnnotation( - builder.libraryBuilder, builder.type)); + type: types.getTypeAnnotation(builder.libraryBuilder, builder.type)); } else { - return new macro.VariableDeclarationImpl( + declaration = new macro.VariableDeclarationImpl( id: macro.RemoteInstance.uniqueId, identifier: new MemberBuilderIdentifier( memberBuilder: builder, @@ -467,29 +535,43 @@ class MacroIntrospection { hasFinal: builder.isFinal, hasInitializer: builder.hasInitializer, hasLate: builder.isLate, - type: types.computeTypeAnnotation( - builder.libraryBuilder, builder.type)); + type: types.getTypeAnnotation(builder.libraryBuilder, builder.type)); } + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.charOffset); + return declaration; } + /// Creates the [macro.TypeParameterDeclarationImpl] corresponding to the + /// nominal type variable [builder] occurring in [libraryBuilder]. macro.TypeParameterDeclarationImpl _createTypeParameterDeclaration( LibraryBuilder libraryBuilder, NominalVariableBuilder nominalVariableBuilder) { final macro.LibraryImpl library = getLibrary(libraryBuilder); - return new macro.TypeParameterDeclarationImpl( - id: macro.RemoteInstance.uniqueId, - identifier: new TypeDeclarationBuilderIdentifier( - typeDeclarationBuilder: nominalVariableBuilder, - libraryBuilder: libraryBuilder, + macro.TypeParameterDeclarationImpl declaration = + new macro.TypeParameterDeclarationImpl( id: macro.RemoteInstance.uniqueId, - name: nominalVariableBuilder.name), - library: library, - // TODO: Provide metadata annotations. - metadata: const [], - bound: types.computeTypeAnnotation( - libraryBuilder, nominalVariableBuilder.bound)); + identifier: new TypeDeclarationBuilderIdentifier( + typeDeclarationBuilder: nominalVariableBuilder, + libraryBuilder: libraryBuilder, + id: macro.RemoteInstance.uniqueId, + name: nominalVariableBuilder.name), + library: library, + // TODO: Provide metadata annotations. + metadata: const [], + bound: nominalVariableBuilder.bound != null + ? types.getTypeAnnotation( + libraryBuilder, nominalVariableBuilder.bound!) + : null); + if (nominalVariableBuilder.fileUri != null) { + _declarationOffsets[declaration] = new UriOffset( + nominalVariableBuilder.fileUri!, nominalVariableBuilder.charOffset); + } + return declaration; } + /// Returns the [macro.TypeParameterDeclarationImpl] corresponding to the + /// nominal type variable [builder] occurring in [libraryBuilder]. macro.TypeParameterDeclarationImpl _getTypeParameterDeclaration( LibraryBuilder libraryBuilder, NominalVariableBuilder nominalVariableBuilder) { @@ -497,11 +579,13 @@ class MacroIntrospection { _createTypeParameterDeclaration(libraryBuilder, nominalVariableBuilder); } + /// Returns the [macro.TypeParameterDeclarationImpl]s corresponding to the + /// nominal [typeParameterBuilders] occurring in [libraryBuilder]. List _nominalVariableBuildersToDeclarations(LibraryBuilder libraryBuilder, List? typeParameterBuilders) { return typeParameterBuilders == null - ? [] + ? const [] : typeParameterBuilders .map((NominalVariableBuilder typeBuilder) => _getTypeParameterDeclaration(libraryBuilder, typeBuilder)) @@ -663,7 +747,7 @@ class _DefinitionPhaseIntrospector extends _DeclarationPhaseIntrospector @override Future inferType( macro.OmittedTypeAnnotation omittedType) => - new Future.value(_introspection.types.inferOmittedType(omittedType)!); + new Future.value(_introspection.types.inferOmittedType(omittedType)); @override Future> topLevelDeclarationsOf( diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart index d96ce721e412..e281e1f1df61 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart @@ -7,6 +7,7 @@ import 'package:_fe_analyzer_shared/src/macros/executor.dart' as macro; import 'package:_fe_analyzer_shared/src/macros/executor/span.dart' as macro; import 'package:_fe_analyzer_shared/src/macros/uri.dart'; import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'; +import 'package:front_end/src/fasta/uri_offset.dart'; import 'package:kernel/ast.dart'; import 'package:kernel/class_hierarchy.dart'; @@ -48,19 +49,18 @@ class MacroDeclarationData { } class MacroApplication { - final Uri fileUri; - final int fileOffset; + final UriOffset uriOffset; final ClassBuilder classBuilder; final String constructorName; final macro.Arguments arguments; final String? errorReason; MacroApplication(this.classBuilder, this.constructorName, this.arguments, - {required this.fileUri, required this.fileOffset}) + {required this.uriOffset}) : errorReason = null; MacroApplication.error(String this.errorReason, this.classBuilder, - {required this.fileUri, required this.fileOffset}) + {required this.uriOffset}) : constructorName = '', arguments = new macro.Arguments(const [], const {}); @@ -226,7 +226,7 @@ void checkMacroApplications( in applicationData.macroApplications) { Map applications = macroApplications[application.classBuilder.cls] ??= {}; - int fileOffset = application.fileOffset; + int fileOffset = application.uriOffset.fileOffset; assert( !applications.containsKey(fileOffset), "Multiple annotations at offset $fileOffset: " @@ -548,16 +548,16 @@ class MacroApplications { // macro interfaces? applicationData.libraryBuilder.addProblem( messageNoMacroApplicationTarget, - application.fileOffset, + application.uriOffset.fileOffset, noLength, - application.fileUri); + application.uriOffset.uri); } else { applicationData.libraryBuilder.addProblem( templateInvalidMacroApplicationTarget.withArguments( DeclarationKindHelper.joinWithOr(supportedKinds)), - application.fileOffset, + application.uriOffset.fileOffset, noLength, - application.fileUri); + application.uriOffset.uri); } } benchmarker?.endSubdivide(); @@ -611,7 +611,8 @@ class MacroApplications { macroApplication.instanceIdentifier, macroTarget, _macroIntrospection.typePhaseIntrospector); - result.reportDiagnostics(macroApplication, applicationData); + result.reportDiagnostics( + _macroIntrospection, macroApplication, applicationData); if (result.isNotEmpty) { _registerMacroExecutionResult(originLibraryBuilder, result); results.add(result); @@ -727,7 +728,8 @@ class MacroApplications { macroApplication.instanceIdentifier, macroTarget, _macroIntrospection.declarationPhaseIntrospector); - result.reportDiagnostics(macroApplication, applicationData); + result.reportDiagnostics( + _macroIntrospection, macroApplication, applicationData); if (result.isNotEmpty) { Map omittedTypes = {}; List spans = []; @@ -846,7 +848,8 @@ class MacroApplications { macroApplication.instanceIdentifier, macroTarget, _macroIntrospection.definitionPhaseIntrospector); - result.reportDiagnostics(macroApplication, applicationData); + result.reportDiagnostics( + _macroIntrospection, macroApplication, applicationData); if (result.isNotEmpty) { _registerMacroExecutionResult(originLibraryBuilder, result); results.add(result); @@ -1010,6 +1013,8 @@ class MacroApplications { _macroIntrospection.clear(); if (!retainDataForTesting) { _libraryData.clear(); + _libraryResults.clear(); + _libraryResultSpans.clear(); } } } @@ -1143,28 +1148,41 @@ extension on macro.MacroExecutionResult { libraryAugmentations.isNotEmpty || typeAugmentations.isNotEmpty; - void reportDiagnostics( + void reportDiagnostics(MacroIntrospection introspection, MacroApplication macroApplication, ApplicationData applicationData) { // TODO(johnniwinther): Should the error be reported on the original // annotation in case of nested macros? - Uri fileUri = macroApplication.fileUri; - int fileOffset = macroApplication.fileOffset; + UriOffset uriOffset = macroApplication.uriOffset; for (macro.Diagnostic diagnostic in diagnostics) { // TODO(johnniwinther): Improve diagnostic reporting. + switch (diagnostic.message.target) { + case null: + break; + case macro.DeclarationDiagnosticTarget(:macro.Declaration declaration): + uriOffset = introspection.getLocationFromDeclaration(declaration); + case macro.TypeAnnotationDiagnosticTarget( + :macro.TypeAnnotation typeAnnotation + ): + uriOffset = introspection.types + .getLocationFromTypeAnnotation(typeAnnotation) ?? + uriOffset; + case macro.MetadataAnnotationDiagnosticTarget(): + // TODO(johnniwinther): Support metadata annotations. + } applicationData.libraryBuilder.addProblem( templateUnspecified.withArguments(diagnostic.message.message), - fileOffset, + uriOffset.fileOffset, -1, - fileUri); + uriOffset.uri); } if (exception != null) { // TODO(johnniwinther): Improve exception reporting. applicationData.libraryBuilder.addProblem( templateUnspecified.withArguments('${exception.runtimeType}: ' '${exception!.message}\n${exception!.stackTrace}'), - fileOffset, + uriOffset.fileOffset, -1, - fileUri); + uriOffset.uri); } } } diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/types.dart b/pkg/front_end/lib/src/fasta/kernel/macro/types.dart index d8222ffd0b05..6f256e7e6f8b 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro/types.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro/types.dart @@ -11,10 +11,14 @@ import 'package:kernel/ast.dart'; import 'package:kernel/src/types.dart'; import 'package:kernel/type_environment.dart' show SubtypeCheckMode; +import '../../builder/declaration_builders.dart'; +import '../../builder/formal_parameter_builder.dart'; import '../../builder/library_builder.dart'; import '../../builder/nullability_builder.dart'; +import '../../builder/record_type_builder.dart'; import '../../builder/type_builder.dart'; import '../../source/source_loader.dart'; +import '../../uri_offset.dart'; import '../hierarchy/hierarchy_builder.dart'; import 'identifiers.dart'; @@ -26,6 +30,7 @@ class MacroTypes { late Types _types; Map _typeAnnotationCache = {}; + Map _typeAnnotationOffsets = {}; Map _staticTypeCache = {}; @@ -38,23 +43,98 @@ class MacroTypes { void clear() { _staticTypeCache.clear(); _typeAnnotationCache.clear(); + _typeAnnotationOffsets.clear(); } - List computeTypeAnnotations( + /// Returns the [UriOffset] for [typeAnnotation], if any. + UriOffset? getLocationFromTypeAnnotation( + macro.TypeAnnotation typeAnnotation) => + _typeAnnotationOffsets[typeAnnotation]; + + /// Returns the list of [macro.TypeAnnotationImpl]s corresponding to + /// [typeBuilders] occurring in [libraryBuilder]. + List getTypeAnnotations( LibraryBuilder library, List? typeBuilders) { if (typeBuilders == null) return const []; return new List.generate(typeBuilders.length, - (int index) => computeTypeAnnotation(library, typeBuilders[index])); + (int index) => getTypeAnnotation(library, typeBuilders[index])); + } + + /// Returns the list of [macro.NamedTypeAnnotationImpl]s corresponding to + /// [typeBuilders] occurring in [libraryBuilder]. + List getNamedTypeAnnotations( + LibraryBuilder library, List? typeBuilders) { + if (typeBuilders == null) return const []; + return new List.generate( + typeBuilders.length, + (int index) => getTypeAnnotation(library, typeBuilders[index]) + as macro.NamedTypeAnnotationImpl); + } + + /// Creates the [macro.FormalParameterImpl]s corresponding to [formals] + /// occurring in [libraryBuilder]. + (List, List) + _createParameters( + LibraryBuilder libraryBuilder, List? formals) { + if (formals == null) { + return const ([], []); + } else { + List positionalParameters = []; + List namedParameters = []; + for (ParameterBuilder formal in formals) { + macro.TypeAnnotationImpl type = + getTypeAnnotation(libraryBuilder, formal.type); + if (formal.isNamed) { + macro.FormalParameterImpl declaration = new macro.FormalParameterImpl( + id: macro.RemoteInstance.uniqueId, + name: formal.name, + // TODO(johnniwinther): Provide metadata annotations. + metadata: const [], + isRequired: formal.isRequiredNamed, + isNamed: true, + type: type, + ); + namedParameters.add(declaration); + } else { + macro.FormalParameterImpl declaration = new macro.FormalParameterImpl( + id: macro.RemoteInstance.uniqueId, + name: formal.name, + // TODO(johnniwinther): Provide metadata annotations. + metadata: const [], + isRequired: formal.isRequiredPositional, + isNamed: false, + type: type, + ); + positionalParameters.add(declaration); + } + } + return (positionalParameters, namedParameters); + } + } + + /// Creates the [macro.RecordFieldDeclarationImpl]s corresponding to [fields] + /// occurring in [libraryBuilder]. + List _createRecordFields( + LibraryBuilder libraryBuilder, List? fields) { + // TODO(johnniwinther): Support record fields once they are not required to + // be declarations. + return const []; } - macro.TypeAnnotationImpl _computeTypeAnnotation( + /// Creates the [macro.TypeAnnotationImpl] corresponding to [typeBuilder] + /// occurring in [libraryBuilder]. + macro.TypeAnnotationImpl _createTypeAnnotation( LibraryBuilder libraryBuilder, TypeBuilder? typeBuilder) { + macro.TypeAnnotationImpl typeAnnotation; + UriOffset? uriOffset = typeBuilder?.fileUri != null + ? new UriOffset(typeBuilder!.fileUri!, typeBuilder.charOffset!) + : null; switch (typeBuilder) { case NamedTypeBuilder(): List typeArguments = - computeTypeAnnotations(libraryBuilder, typeBuilder.typeArguments); + getTypeAnnotations(libraryBuilder, typeBuilder.typeArguments); bool isNullable = typeBuilder.nullabilityBuilder.isNullable; - return new macro.NamedTypeAnnotationImpl( + typeAnnotation = new macro.NamedTypeAnnotationImpl( id: macro.RemoteInstance.uniqueId, identifier: new TypeBuilderIdentifier( typeBuilder: typeBuilder, @@ -64,29 +144,74 @@ class MacroTypes { typeArguments: typeArguments, isNullable: isNullable); case OmittedTypeBuilder(): - return new _OmittedTypeAnnotationImpl(typeBuilder, + typeAnnotation = new _OmittedTypeAnnotationImpl(typeBuilder, id: macro.RemoteInstance.uniqueId); - case FunctionTypeBuilder(): - case InvalidTypeBuilder(): - case RecordTypeBuilder(): - case FixedTypeBuilder(): + case FunctionTypeBuilder( + :TypeBuilder returnType, + :List? formals, + :List? typeVariables + ): + bool isNullable = typeBuilder.nullabilityBuilder.isNullable; + var ( + List positionalParameters, + List namedParameters + ) = _createParameters(libraryBuilder, formals); + List typeParameters = []; + if (typeVariables != null) { + for (StructuralVariableBuilder typeVariable in typeVariables) { + typeParameters.add(new macro.TypeParameterImpl( + id: macro.RemoteInstance.uniqueId, + bound: typeVariable.bound != null + ? _createTypeAnnotation(libraryBuilder, typeVariable.bound) + : null, + metadata: const [], + name: typeVariable.name)); + } + } + typeAnnotation = new macro.FunctionTypeAnnotationImpl( + id: macro.RemoteInstance.uniqueId, + isNullable: isNullable, + namedParameters: namedParameters, + positionalParameters: positionalParameters, + returnType: getTypeAnnotation(libraryBuilder, returnType), + typeParameters: typeParameters); + case RecordTypeBuilder( + :List? positionalFields, + :List? namedFields + ): + bool isNullable = typeBuilder.nullabilityBuilder.isNullable; + typeAnnotation = new macro.RecordTypeAnnotationImpl( + id: macro.RemoteInstance.uniqueId, + isNullable: isNullable, + positionalFields: + _createRecordFields(libraryBuilder, positionalFields), + namedFields: _createRecordFields(libraryBuilder, namedFields)); case null: - // TODO(johnniwinther): Should this only be for `null`? Can the other - // type builders be observed here? + // TODO(johnniwinther): Is this an error case? return new macro.NamedTypeAnnotationImpl( id: macro.RemoteInstance.uniqueId, identifier: omittedTypeIdentifier, isNullable: false, typeArguments: const []); + case InvalidTypeBuilder(): + case FixedTypeBuilder(): + throw new UnsupportedError("Unexpected type builder $typeBuilder"); + } + if (uriOffset != null) { + _typeAnnotationOffsets[typeAnnotation] = uriOffset; } + return typeAnnotation; } - macro.TypeAnnotationImpl computeTypeAnnotation( + /// Returns the [macro.TypeAnnotationImpl] corresponding to [typeBuilder] + /// occurring in [libraryBuilder]. + macro.TypeAnnotationImpl getTypeAnnotation( LibraryBuilder libraryBuilder, TypeBuilder? typeBuilder) { return _typeAnnotationCache[typeBuilder] ??= - _computeTypeAnnotation(libraryBuilder, typeBuilder); + _createTypeAnnotation(libraryBuilder, typeBuilder); } + /// Returns the [DartType] corresponding to [typeAnnotation]. DartType _typeForAnnotation(macro.TypeAnnotationCode typeAnnotation) { NullabilityBuilder nullabilityBuilder; if (typeAnnotation is macro.NullableTypeAnnotationCode) { @@ -110,40 +235,41 @@ class MacroTypes { 'Unimplemented type annotation kind ${typeAnnotation.kind}'); } + /// Returns the resolved [macro.StaticType] for [typeAnnotation]. macro.StaticType resolveTypeAnnotation( macro.TypeAnnotationCode typeAnnotation) { - return createStaticType(_typeForAnnotation(typeAnnotation)); + return _createStaticType(_typeForAnnotation(typeAnnotation)); } - macro.StaticType createStaticType(DartType dartType) { + /// Creates the [macro.StaticType] corresponding to [dartType]. + macro.StaticType _createStaticType(DartType dartType) { return _staticTypeCache[dartType] ??= new _StaticTypeImpl(_types, dartType); } - List typeBuildersToAnnotations( - LibraryBuilder libraryBuilder, List? typeBuilders) { - return typeBuilders == null - ? [] - : typeBuilders - .map((TypeBuilder typeBuilder) => - computeTypeAnnotation(libraryBuilder, typeBuilder) - as macro.NamedTypeAnnotationImpl) - .toList(); - } - + /// Returns the [macro.TypeAnnotation] for the inferred type of [omittedType], + /// or `null` if the type has not yet been inferred. macro.TypeAnnotation? inferOmittedType( macro.OmittedTypeAnnotation omittedType) { if (omittedType is _OmittedTypeAnnotationImpl) { OmittedTypeBuilder typeBuilder = omittedType.typeBuilder; if (typeBuilder.hasType) { - return computeTypeAnnotation( + return getTypeAnnotation( _sourceLoader.coreLibrary, _sourceLoader.target.dillTarget.loader .computeTypeBuilder(typeBuilder.type)); } + return null; } - return null; + throw new UnsupportedError( + "Unexpected OmittedTypeAnnotation implementation " + "${omittedType.runtimeType}."); } + /// Computes a map of the [OmittedTypeBuilder]s corresponding to the + /// [macro.OmittedTypeAnnotation]s in [omittedTypes]. The synthesized names + /// in [omittedTypes] are used as the keys in the returned map. + /// + /// If [omittedTypes] is empty, `null` is returned. Map? computeOmittedTypeBuilders( Map omittedTypes) { if (omittedTypes.isEmpty) { diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt index 26b0af84e212..afe8388af276 100644 --- a/pkg/front_end/test/spell_checking_list_code.txt +++ b/pkg/front_end/test/spell_checking_list_code.txt @@ -180,6 +180,7 @@ bother boundarykey boundness boxed +breach breadcrumbs brevity brianwilkerson diff --git a/pkg/front_end/test/static_types/cfe_allowed.json b/pkg/front_end/test/static_types/cfe_allowed.json index 6dd2207dd547..7ef3f9f09dc6 100644 --- a/pkg/front_end/test/static_types/cfe_allowed.json +++ b/pkg/front_end/test/static_types/cfe_allowed.json @@ -8,7 +8,7 @@ "Dynamic invocation of 'split'.": 1 }, "pkg/_fe_analyzer_shared/lib/src/util/runtimes.dart": { - "Dynamic access of 'createUriForKernelBlob'.": 1 + "Dynamic invocation of 'createUriForKernelBlob'.": 1 }, "pkg/front_end/lib/src/macros/isolate_macro_serializer.dart": { "Dynamic invocation of 'unregisterKernelBlobUri'.": 1, diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect index eaa994c45e0d..a3b77e3f1df4 100644 --- a/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect @@ -9,81 +9,63 @@ static method method(core::Iterable iterable) → core::Iterable stream) → asy::Stream { - synthesized asy::StreamController #controller = asy::StreamController::•(); + synthesized asy::StreamController #controller = asy::StreamController::•(sync: #C1); synthesized () → asy::Future #body = () → asy::Future async /* emittedValueType= void */ { - core::bool :async_temporary_0; - core::bool :async_temporary_1; - core::bool :async_temporary_2; - core::bool :async_temporary_3; - core::bool :async_temporary_4; - dynamic :async_temporary_5; - synthesized asy::Completer #completer = asy::Completer::•(); - #controller.{asy::StreamController::add}(#completer){(core::Object?) → void}; + void :async_temporary_0; + void :async_temporary_1; + dynamic :async_temporary_2; + synthesized asy::Completer? #paused; + dynamic #onCancelCallback = () → void { + if(#paused == null) { + } + else { + #paused.{asy::Completer::complete}(#C2){([FutureOr?]) → void}; + #paused = #C2; + } + }; + #controller.{asy::StreamController::onResume} = #onCancelCallback; + #controller.{asy::StreamController::onCancel} = #onCancelCallback; { core::int #t1 = 0; core::Object #t2; core::StackTrace #t3; try try { - :async_temporary_0 = await #completer.{asy::Completer::future}{asy::Future}; - :async_temporary_0 as{ForLegacy} dynamic; { - { - #controller.{asy::StreamController::add}(1){(core::Object?) → void}; - #completer = asy::Completer::•(); - #controller.{asy::StreamController::add}(#completer){(core::Object?) → void}; - :async_temporary_1 = await #completer.{asy::Completer::future}{asy::Future}; + #controller.{asy::StreamController::add}(1){(core::Object?) → void}; + if(#controller.{asy::StreamController::isPaused}{core::bool}) { + :async_temporary_0 = await(#paused = asy::Completer::•()).{asy::Completer::future}{asy::Future}; + :async_temporary_0 as{ForLegacy} dynamic; + } + if(#controller.{asy::StreamController::hasListener}{core::bool}) { + } + else + return; + } + { + #controller.{asy::StreamController::add}(2){(core::Object?) → void}; + if(#controller.{asy::StreamController::isPaused}{core::bool}) { + :async_temporary_1 = await(#paused = asy::Completer::•()).{asy::Completer::future}{asy::Future}; :async_temporary_1 as{ForLegacy} dynamic; } - { - #controller.{asy::StreamController::add}(2){(core::Object?) → void}; - #completer = asy::Completer::•(); - #controller.{asy::StreamController::add}(#completer){(core::Object?) → void}; - :async_temporary_2 = await #completer.{asy::Completer::future}{asy::Future}; - :async_temporary_2 as{ForLegacy} dynamic; + if(#controller.{asy::StreamController::hasListener}{core::bool}) { } - { - synthesized asy::_StreamIterator #forIterator = new asy::_StreamIterator::•(stream); - synthesized core::bool #jumpSentinel = #C1; - { - core::int #t4 = 0; - core::Object #t5; - core::StackTrace #t6; - try { - #L1: - for (; ; ) { - :async_temporary_4 = await #forIterator.{asy::_StreamIterator::moveNext}(){() → asy::Future}; - if(#jumpSentinel = :async_temporary_4 as{ForLegacy} dynamic) { - synthesized core::int #awaitForVar = #forIterator.{asy::_StreamIterator::current}{core::int}; - { - #controller.{asy::StreamController::add}(#awaitForVar){(core::Object?) → void}; - #completer = asy::Completer::•(); - #controller.{asy::StreamController::add}(#completer){(core::Object?) → void}; - :async_temporary_3 = await #completer.{asy::Completer::future}{asy::Future}; - :async_temporary_3 as{ForLegacy} dynamic; - } - } - else - break #L1; - } - } - finally { - if(#jumpSentinel) { - :async_temporary_5 = await #forIterator.{asy::_StreamIterator::cancel}(){() → asy::Future}; - :async_temporary_5; - } - #t4; - #t5; - #t6; - } - } + else + return; + } + { + :async_temporary_2 = await #controller.{asy::StreamController::addStream}(stream){(asy::Stream, {cancelOnError: core::bool?}) → asy::Future}; + :async_temporary_2; + if(#controller.{asy::StreamController::hasListener}{core::bool}) { } + else + return; } } - on dynamic catch(dynamic #t7, core::StackTrace #t8) { - #controller.{asy::StreamController::addError}(#t7, #t8){(core::Object, [core::StackTrace?]) → void}; - #t7; - #t8; + on dynamic catch(dynamic #t4, core::StackTrace #t5) { + #controller.{asy::StreamController::addError}(#t4, #t5){(core::Object, [core::StackTrace?]) → void}; + #t4; + #t5; } finally { #controller.{asy::StreamController::close}(){() → asy::Future}; @@ -93,30 +75,13 @@ static method asyncMethod(asy::Stream stream) → asy::Stream}.{asy::Stream::asyncMap}((synthesized core::Object? value) → FutureOr async /* emittedValueType= core::Object? */ { - if(#isFirst) { - #body(){() → asy::Future}; - return #C3; - } - if(!#isEven) - value.{asy::Completer::complete}(#C2){([FutureOr?]) → void}; - return value; - }){((core::Object?) → FutureOr) → asy::Stream}.{asy::Stream::where}((synthesized core::Object? value) → core::bool { - if(#isFirst) { - #isFirst = #C1; - return #C1; - } - synthesized core::bool keep = #isEven; - #isEven = !#isEven; - return keep; - }){((core::Object?) → core::bool) → asy::Stream}.{asy::Stream::cast}(){() → asy::Stream}; + #controller.{asy::StreamController::onListen} = () → dynamic + asy::scheduleMicrotask(#body); +; + return #controller.{asy::StreamController::stream}{asy::Stream}; } constants { - #C1 = false - #C2 = true - #C3 = null + #C1 = true + #C2 = null } diff --git a/tests/co19/co19-dart2wasm.status b/tests/co19/co19-dart2wasm.status index 73cfa1f467a4..8e96ee9d4f9d 100644 --- a/tests/co19/co19-dart2wasm.status +++ b/tests/co19/co19-dart2wasm.status @@ -17,6 +17,3 @@ LibTest/mirrors/*: SkipByDesign # dart:mirrors is not supported. [ $compiler == dart2wasm && $runtime == chrome ] Language/Expressions/Function_Invocation/async_generator_invokation_t10: SkipSlow # Issue(http://dartbug.com/55025) -Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t03: SkipSlow # Issue(http://dartbug.com/55025) -Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t07: SkipSlow # Issue(http://dartbug.com/55025) -Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t11: SkipSlow # Issue(http://dartbug.com/55025) diff --git a/tests/language/language_dart2wasm.status b/tests/language/language_dart2wasm.status index 7918e2c2dc52..9af854a66b83 100644 --- a/tests/language/language_dart2wasm.status +++ b/tests/language/language_dart2wasm.status @@ -8,9 +8,5 @@ inference_update_2/why_not_promoted_external_error_test: SkipByDesign # Non-JS-i number/web_int_literals_test: SkipByDesign # WASM has real integers. vm/*: SkipByDesign # Tests for the VM. -[ $compiler == dart2wasm && $runtime == chrome ] -async_star/yield_test: SkipSlow # Issue(http://dartbug.com/55025) -async_star/yieldstar_test: SkipSlow # Issue(http://dartbug.com/55025) - [ $compiler == dart2wasm && $runtime == d8 ] import/conditional_string_test: SkipByDesign # No XHR in d8 diff --git a/tools/VERSION b/tools/VERSION index 0625116c0c6a..8adce1b1a586 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -27,5 +27,5 @@ CHANNEL dev MAJOR 3 MINOR 4 PATCH 0 -PRERELEASE 200 +PRERELEASE 201 PRERELEASE_PATCH 0 diff --git a/tools/build.py b/tools/build.py index c26be7d971c4..89a5522e5b26 100755 --- a/tools/build.py +++ b/tools/build.py @@ -161,21 +161,6 @@ def StartRBE(out_dir, use_goma, env): if not os.path.exists(rbe_dir) or not os.path.isdir(rbe_dir): print(f'Could not find {rbe} at {rbe_dir}') return False - RBE_cfg = 'RBE_CFG' if HOST_OS == 'win32' else 'RBE_cfg' - RBE_server_address = ('RBE_SERVER_ADDRESS' - if HOST_OS == 'win32' else 'RBE_server_address') - if not use_goma and not RBE_cfg in env: - env[RBE_cfg] = os.path.join( - os.getcwd(), 'build', 'rbe', - 'windows.cfg' if HOST_OS == 'win32' else 'unix.cfg') - if not use_goma and not RBE_server_address in env: - with open(env[RBE_cfg], 'r') as f: - if not any([l.startswith('server_address') for l in f.readlines()]): - schema = 'pipe' if HOST_OS == 'win32' else 'unix' - socket = os.path.join(os.getcwd(), out_dir, 'reproxy.sock') - if HOST_OS == 'win32': - socket = socket.replace('\\', '_').replace(':', '_') - env[RBE_server_address] = f'{schema}://{socket}' bootstrap = 'goma_ctl.py' if use_goma else 'bootstrap' bootstrap_path = os.path.join(rbe_dir, bootstrap) bootstrap_command = [bootstrap_path] @@ -191,12 +176,12 @@ def StartRBE(out_dir, use_goma, env): return True -def StopRBE(): +def StopRBE(env): global rbe_started, bootstrap_path if rbe_started != 'rbe': return bootstrap_command = [bootstrap_path, '--shutdown'] - process = subprocess.Popen(bootstrap_command) + process = subprocess.Popen(bootstrap_command, env=env) process.wait() @@ -342,7 +327,7 @@ def Main(): env.pop('SDKROOT', None) # Always run GN before building. - gn_py.RunGnOnConfiguredConfigurations(options) + gn_py.RunGnOnConfiguredConfigurations(options, env) # Build all targets for each requested configuration. configs = [] @@ -356,7 +341,7 @@ def Main(): exit_code = Build(configs, env, options) - StopRBE() + StopRBE(env) if exit_code == 0: endtime = time.time() diff --git a/tools/gn.py b/tools/gn.py index 8b22bbb32650..e2116e9e45a5 100755 --- a/tools/gn.py +++ b/tools/gn.py @@ -621,6 +621,26 @@ def parse_args(args): return options +def InitializeRBE(out_dir, env): + RBE_cfg = 'RBE_CFG' if HOST_OS == 'win32' else 'RBE_cfg' + RBE_server_address = ('RBE_SERVER_ADDRESS' + if HOST_OS == 'win32' else 'RBE_server_address') + # Default RBE_cfg to the appropriate configuration file. + if not RBE_cfg in env: + env[RBE_cfg] = os.path.join( + os.getcwd(), 'build', 'rbe', + 'windows.cfg' if HOST_OS == 'win32' else 'unix.cfg') + # Default RBE_server_address to inside the build directory. + if not RBE_server_address in env: + with open(env[RBE_cfg], 'r') as f: + if not any([l.startswith('server_address') for l in f.readlines()]): + schema = 'pipe' if HOST_OS == 'win32' else 'unix' + socket = os.path.join(os.getcwd(), out_dir, 'reproxy.sock') + if HOST_OS == 'win32': + socket = socket.replace('\\', '_').replace(':', '_') + env[RBE_server_address] = f'{schema}://{socket}' + + def ExecutableName(basename): if utils.IsWindows(): return f'{basename}.exe' @@ -652,13 +672,17 @@ def BuildGnCommand(args, mode, arch, target_os, sanitizer, out_dir): return command -def RunGnOnConfiguredConfigurations(args): +def RunGnOnConfiguredConfigurations(args, env={}): + initialized_rbe = False commands = [] for target_os in args.os: for mode in args.mode: for arch in args.arch: for sanitizer in args.sanitizer: out_dir = GetOutDir(mode, arch, target_os, sanitizer) + if args.rbe and not initialized_rbe: + InitializeRBE(out_dir, env) + initialized_rbe = True commands.append( BuildGnCommand(args, mode, arch, target_os, sanitizer, out_dir)) @@ -674,7 +698,7 @@ def cleanup(command): for command in commands: try: - process = subprocess.Popen(command, cwd=DART_ROOT) + process = subprocess.Popen(command, cwd=DART_ROOT, env=env) active_commands.append([command, process]) except Exception as e: print('Error: %s' % e)