| // 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. | 
 |  | 
 | // @dart = 2.9 | 
 |  | 
 | import 'package:kernel/ast.dart'; | 
 | import 'package:kernel/core_types.dart'; | 
 |  | 
 | import '../../base/nnbd_mode.dart'; | 
 | import '../source/source_library_builder.dart'; | 
 | import '../names.dart'; | 
 |  | 
 | const String lateFieldPrefix = '_#'; | 
 | const String lateIsSetSuffix = '#isSet'; | 
 | const String lateLocalPrefix = '#'; | 
 | const String lateLocalGetterSuffix = '#get'; | 
 | const String lateLocalSetterSuffix = '#set'; | 
 |  | 
 | /// Creates the body for the synthesized getter used to encode the lowering | 
 | /// of a late non-final field or local with an initializer. | 
 | /// | 
 | /// Late final fields and locals need to detect writes during initialization and | 
 | /// therefore uses [createGetterWithInitializerWithRecheck] instead. | 
 | Statement createGetterWithInitializer( | 
 |     CoreTypes coreTypes, | 
 |     int fileOffset, | 
 |     String name, | 
 |     DartType type, | 
 |     Expression initializer, | 
 |     bool useNewMethodInvocationEncoding, | 
 |     {Expression createVariableRead({bool needsPromotion}), | 
 |     Expression createVariableWrite(Expression value), | 
 |     Expression createIsSetRead(), | 
 |     Expression createIsSetWrite(Expression value), | 
 |     IsSetEncoding isSetEncoding}) { | 
 |   assert(isSetEncoding != null); | 
 |   switch (isSetEncoding) { | 
 |     case IsSetEncoding.useIsSetField: | 
 |       // Generate: | 
 |       // | 
 |       //    if (!_#isSet#field) { | 
 |       //      _#field = <init>; | 
 |       //      _#isSet#field = true | 
 |       //    } | 
 |       //    return _#field; | 
 |       return new Block(<Statement>[ | 
 |         new IfStatement( | 
 |             new Not(createIsSetRead()..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset, | 
 |             new Block(<Statement>[ | 
 |               new ExpressionStatement( | 
 |                   createVariableWrite(initializer)..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |               new ExpressionStatement( | 
 |                   createIsSetWrite( | 
 |                       new BoolLiteral(true)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |             ]), | 
 |             null) | 
 |           ..fileOffset = fileOffset, | 
 |         new ReturnStatement( | 
 |             // If [type] is a type variable with undetermined nullability we | 
 |             // need to create a read of the field that is promoted to the type | 
 |             // variable type. | 
 |             createVariableRead(needsPromotion: type.isPotentiallyNonNullable)) | 
 |           ..fileOffset = fileOffset | 
 |       ]) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useSentinel: | 
 |       // Generate: | 
 |       // | 
 |       //    return let # = _#field in isSentinel(#) ? _#field = <init> : #; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead(needsPromotion: false)..fileOffset = fileOffset, | 
 |           type: type.withDeclaredNullability(Nullability.nullable)) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement( | 
 |           new Let( | 
 |               variable, | 
 |               new ConditionalExpression( | 
 |                   new StaticInvocation( | 
 |                       coreTypes.isSentinelMethod, | 
 |                       new Arguments(<Expression>[ | 
 |                         new VariableGet(variable)..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset, | 
 |                   createVariableWrite(initializer)..fileOffset = fileOffset, | 
 |                   new VariableGet(variable, type)..fileOffset = fileOffset, | 
 |                   type) | 
 |                 ..fileOffset = fileOffset) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useNull: | 
 |       // Generate: | 
 |       // | 
 |       //    return let # = _#field in # == null ? _#field = <init> : #; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead(needsPromotion: false)..fileOffset = fileOffset, | 
 |           type: type.withDeclaredNullability(Nullability.nullable)) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement(new Let( | 
 |           variable, | 
 |           new ConditionalExpression( | 
 |               useNewMethodInvocationEncoding | 
 |                   ? (new EqualsNull( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                   : new MethodInvocation( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset, | 
 |                       equalsName, | 
 |                       new Arguments(<Expression>[ | 
 |                         new NullLiteral()..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |               createVariableWrite(initializer)..fileOffset = fileOffset, | 
 |               new VariableGet(variable, type)..fileOffset = fileOffset, | 
 |               type) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding"); | 
 | } | 
 |  | 
 | /// Creates the body for the synthesized getter used to encode the lowering | 
 | /// of a late final field or local with an initializer. | 
 | Statement createGetterWithInitializerWithRecheck( | 
 |     CoreTypes coreTypes, | 
 |     int fileOffset, | 
 |     String name, | 
 |     DartType type, | 
 |     Expression initializer, | 
 |     bool useNewMethodInvocationEncoding, | 
 |     {Expression createVariableRead({bool needsPromotion}), | 
 |     Expression createVariableWrite(Expression value), | 
 |     Expression createIsSetRead(), | 
 |     Expression createIsSetWrite(Expression value), | 
 |     IsSetEncoding isSetEncoding, | 
 |     bool forField}) { | 
 |   assert(forField != null); | 
 |   Constructor constructor = forField | 
 |       ? coreTypes.lateInitializationFieldAssignedDuringInitializationConstructor | 
 |       : coreTypes | 
 |           .lateInitializationLocalAssignedDuringInitializationConstructor; | 
 |   Expression exception = new Throw( | 
 |       new ConstructorInvocation( | 
 |           constructor, | 
 |           new Arguments( | 
 |               <Expression>[new StringLiteral(name)..fileOffset = fileOffset]) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |     ..fileOffset = fileOffset; | 
 |   VariableDeclaration temp = | 
 |       new VariableDeclaration.forValue(initializer, type: type) | 
 |         ..fileOffset = fileOffset; | 
 |   switch (isSetEncoding) { | 
 |     case IsSetEncoding.useIsSetField: | 
 |       // Generate: | 
 |       // | 
 |       //    if (!_#isSet#field) { | 
 |       //      var temp = <init>; | 
 |       //      if (_#isSet#field) throw '...' | 
 |       //      _#field = temp; | 
 |       //      _#isSet#field = true | 
 |       //    } | 
 |       //    return _#field; | 
 |       return new Block(<Statement>[ | 
 |         new IfStatement( | 
 |             new Not(createIsSetRead()..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset, | 
 |             new Block(<Statement>[ | 
 |               temp, | 
 |               new IfStatement( | 
 |                   createIsSetRead()..fileOffset = fileOffset, | 
 |                   new ExpressionStatement(exception)..fileOffset = fileOffset, | 
 |                   null) | 
 |                 ..fileOffset = fileOffset, | 
 |               new ExpressionStatement( | 
 |                   createVariableWrite( | 
 |                       new VariableGet(temp)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |               new ExpressionStatement( | 
 |                   createIsSetWrite( | 
 |                       new BoolLiteral(true)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |             ]), | 
 |             null) | 
 |           ..fileOffset = fileOffset, | 
 |         new ReturnStatement( | 
 |             // If [type] is a type variable with undetermined nullability we | 
 |             // need to create a read of the field that is promoted to the type | 
 |             // variable type. | 
 |             createVariableRead(needsPromotion: type.isPotentiallyNonNullable)) | 
 |           ..fileOffset = fileOffset | 
 |       ]) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useSentinel: | 
 |       // Generate: | 
 |       // | 
 |       //    return let #1 = _#field in isSentinel(#1) | 
 |       //        ? let #2 = <init> in isSentinel(_#field) | 
 |       //            ? _#field = #2 : throw '...' | 
 |       //        : #1; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead(needsPromotion: false)..fileOffset = fileOffset, | 
 |           type: type) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement( | 
 |           new Let( | 
 |               variable, | 
 |               new ConditionalExpression( | 
 |                   new StaticInvocation( | 
 |                       coreTypes.isSentinelMethod, | 
 |                       new Arguments(<Expression>[ | 
 |                         new VariableGet(variable)..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset, | 
 |                   new Let( | 
 |                       temp, | 
 |                       new ConditionalExpression( | 
 |                           new StaticInvocation( | 
 |                               coreTypes.isSentinelMethod, | 
 |                               new Arguments(<Expression>[ | 
 |                                 createVariableRead(needsPromotion: false) | 
 |                                   ..fileOffset = fileOffset | 
 |                               ]) | 
 |                                 ..fileOffset = fileOffset) | 
 |                             ..fileOffset = fileOffset, | 
 |                           createVariableWrite( | 
 |                               new VariableGet(temp)..fileOffset = fileOffset) | 
 |                             ..fileOffset = fileOffset, | 
 |                           exception, | 
 |                           type) | 
 |                         ..fileOffset = fileOffset), | 
 |                   new VariableGet(variable)..fileOffset = fileOffset, | 
 |                   type) | 
 |                 ..fileOffset = fileOffset) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useNull: | 
 |       // Generate: | 
 |       // | 
 |       //    return let #1 = _#field in #1 == null | 
 |       //        ? let #2 = <init> in _#field == null | 
 |       //            ? _#field = #2 : throw '...' | 
 |       //        : #1; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead(needsPromotion: false)..fileOffset = fileOffset, | 
 |           type: type.withDeclaredNullability(Nullability.nullable)) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement(new Let( | 
 |           variable, | 
 |           new ConditionalExpression( | 
 |               useNewMethodInvocationEncoding | 
 |                   ? (new EqualsNull( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                   : new MethodInvocation( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset, | 
 |                       equalsName, | 
 |                       new Arguments(<Expression>[ | 
 |                         new NullLiteral()..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |               new Let( | 
 |                   temp, | 
 |                   new ConditionalExpression( | 
 |                       useNewMethodInvocationEncoding | 
 |                           ? (new EqualsNull( | 
 |                               createVariableRead(needsPromotion: false) | 
 |                                 ..fileOffset = fileOffset) | 
 |                             ..fileOffset = fileOffset) | 
 |                           : new MethodInvocation( | 
 |                               createVariableRead(needsPromotion: false) | 
 |                                 ..fileOffset = fileOffset, | 
 |                               equalsName, | 
 |                               new Arguments(<Expression>[ | 
 |                                 new NullLiteral()..fileOffset = fileOffset | 
 |                               ]) | 
 |                                 ..fileOffset = fileOffset) | 
 |                         ..fileOffset = fileOffset, | 
 |                       createVariableWrite( | 
 |                           new VariableGet(temp)..fileOffset = fileOffset) | 
 |                         ..fileOffset = fileOffset, | 
 |                       exception, | 
 |                       type) | 
 |                     ..fileOffset = fileOffset), | 
 |               new VariableGet(variable, type)..fileOffset = fileOffset, | 
 |               type) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding"); | 
 | } | 
 |  | 
 | /// Creates the body for the synthesized getter used to encode the lowering | 
 | /// of a late field or local without an initializer. | 
 | Statement createGetterBodyWithoutInitializer( | 
 |     CoreTypes coreTypes, | 
 |     int fileOffset, | 
 |     String name, | 
 |     DartType type, | 
 |     bool useNewMethodInvocationEncoding, | 
 |     {Expression createVariableRead({bool needsPromotion}), | 
 |     Expression createIsSetRead(), | 
 |     IsSetEncoding isSetEncoding, | 
 |     bool forField}) { | 
 |   assert(forField != null); | 
 |   assert(isSetEncoding != null); | 
 |   Expression exception = new Throw( | 
 |       new ConstructorInvocation( | 
 |           forField | 
 |               ? coreTypes.lateInitializationFieldNotInitializedConstructor | 
 |               : coreTypes.lateInitializationLocalNotInitializedConstructor, | 
 |           new Arguments( | 
 |               <Expression>[new StringLiteral(name)..fileOffset = fileOffset]) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |     ..fileOffset = fileOffset; | 
 |   switch (isSetEncoding) { | 
 |     case IsSetEncoding.useIsSetField: | 
 |       // Generate: | 
 |       // | 
 |       //    return _#isSet#field ? _#field : throw '...'; | 
 |       return new ReturnStatement( | 
 |           new ConditionalExpression( | 
 |               createIsSetRead()..fileOffset = fileOffset, | 
 |               createVariableRead(needsPromotion: type.isPotentiallyNonNullable) | 
 |                 ..fileOffset = fileOffset, | 
 |               exception, | 
 |               type) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useSentinel: | 
 |       // Generate: | 
 |       // | 
 |       //    return let # = _#field in isSentinel(#) ? throw '...' : #; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead()..fileOffset = fileOffset, | 
 |           type: type.withDeclaredNullability(Nullability.nullable)) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement( | 
 |           new Let( | 
 |               variable, | 
 |               new ConditionalExpression( | 
 |                   new StaticInvocation( | 
 |                       coreTypes.isSentinelMethod, | 
 |                       new Arguments(<Expression>[ | 
 |                         new VariableGet(variable)..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset, | 
 |                   exception, | 
 |                   new VariableGet(variable, type)..fileOffset = fileOffset, | 
 |                   type) | 
 |                 ..fileOffset = fileOffset) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useNull: | 
 |       // Generate: | 
 |       // | 
 |       //    return let # = _#field in # == null ? throw '...' : #; | 
 |       VariableDeclaration variable = new VariableDeclaration.forValue( | 
 |           createVariableRead()..fileOffset = fileOffset, | 
 |           type: type.withDeclaredNullability(Nullability.nullable)) | 
 |         ..fileOffset = fileOffset; | 
 |       return new ReturnStatement(new Let( | 
 |           variable, | 
 |           new ConditionalExpression( | 
 |               useNewMethodInvocationEncoding | 
 |                   ? (new EqualsNull( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset) | 
 |                     ..fileOffset = fileOffset) | 
 |                   : new MethodInvocation( | 
 |                       new VariableGet(variable)..fileOffset = fileOffset, | 
 |                       equalsName, | 
 |                       new Arguments(<Expression>[ | 
 |                         new NullLiteral()..fileOffset = fileOffset | 
 |                       ]) | 
 |                         ..fileOffset = fileOffset) | 
 |                 ..fileOffset = fileOffset, | 
 |               exception, | 
 |               new VariableGet(variable, type)..fileOffset = fileOffset, | 
 |               type) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding"); | 
 | } | 
 |  | 
 | /// Creates the body for the synthesized setter used to encode the lowering | 
 | /// of a non-final late field or local. | 
 | Statement createSetterBody(CoreTypes coreTypes, int fileOffset, String name, | 
 |     VariableDeclaration parameter, DartType type, | 
 |     {bool shouldReturnValue, | 
 |     Expression createVariableWrite(Expression value), | 
 |     Expression createIsSetWrite(Expression value), | 
 |     IsSetEncoding isSetEncoding}) { | 
 |   assert(isSetEncoding != null); | 
 |   Statement createReturn(Expression value) { | 
 |     if (shouldReturnValue) { | 
 |       return new ReturnStatement(value)..fileOffset = fileOffset; | 
 |     } else { | 
 |       return new ExpressionStatement(value)..fileOffset = fileOffset; | 
 |     } | 
 |   } | 
 |  | 
 |   Statement assignment = createReturn( | 
 |       createVariableWrite(new VariableGet(parameter)..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset); | 
 |  | 
 |   switch (isSetEncoding) { | 
 |     case IsSetEncoding.useIsSetField: | 
 |       // Generate: | 
 |       // | 
 |       //    _#isSet#field = true; | 
 |       //    return _#field = parameter | 
 |       // | 
 |       return new Block([ | 
 |         new ExpressionStatement( | 
 |             createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset) | 
 |           ..fileOffset = fileOffset, | 
 |         assignment | 
 |       ]) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useSentinel: | 
 |     case IsSetEncoding.useNull: | 
 |       // Generate: | 
 |       // | 
 |       //    return _#field = parameter | 
 |       // | 
 |       return assignment; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding"); | 
 | } | 
 |  | 
 | /// Creates the body for the synthesized setter used to encode the lowering | 
 | /// of a final late field or local. | 
 | Statement createSetterBodyFinal( | 
 |     CoreTypes coreTypes, | 
 |     int fileOffset, | 
 |     String name, | 
 |     VariableDeclaration parameter, | 
 |     DartType type, | 
 |     bool useNewMethodInvocationEncoding, | 
 |     {bool shouldReturnValue, | 
 |     Expression createVariableRead(), | 
 |     Expression createVariableWrite(Expression value), | 
 |     Expression createIsSetRead(), | 
 |     Expression createIsSetWrite(Expression value), | 
 |     IsSetEncoding isSetEncoding, | 
 |     bool forField}) { | 
 |   assert(forField != null); | 
 |   assert(isSetEncoding != null); | 
 |   Expression exception = new Throw( | 
 |       new ConstructorInvocation( | 
 |           forField | 
 |               ? coreTypes.lateInitializationFieldAlreadyInitializedConstructor | 
 |               : coreTypes.lateInitializationLocalAlreadyInitializedConstructor, | 
 |           new Arguments( | 
 |               <Expression>[new StringLiteral(name)..fileOffset = fileOffset]) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset) | 
 |     ..fileOffset = fileOffset; | 
 |  | 
 |   Statement createReturn(Expression value) { | 
 |     if (shouldReturnValue) { | 
 |       return new ReturnStatement(value)..fileOffset = fileOffset; | 
 |     } else { | 
 |       return new ExpressionStatement(value)..fileOffset = fileOffset; | 
 |     } | 
 |   } | 
 |  | 
 |   switch (isSetEncoding) { | 
 |     case IsSetEncoding.useIsSetField: | 
 |       // Generate: | 
 |       // | 
 |       //    if (_#isSet#field) { | 
 |       //      throw '...'; | 
 |       //    } else | 
 |       //      _#isSet#field = true; | 
 |       //      return _#field = parameter | 
 |       //    } | 
 |       return new IfStatement( | 
 |           createIsSetRead()..fileOffset = fileOffset, | 
 |           new ExpressionStatement(exception)..fileOffset = fileOffset, | 
 |           new Block([ | 
 |             new ExpressionStatement( | 
 |                 createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset) | 
 |                   ..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset, | 
 |             createReturn(createVariableWrite( | 
 |                 new VariableGet(parameter)..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset) | 
 |           ]) | 
 |             ..fileOffset = fileOffset) | 
 |         ..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useSentinel: | 
 |       // Generate: | 
 |       // | 
 |       //    if (isSentinel(_#field)) { | 
 |       //      return _#field = parameter; | 
 |       //    } else { | 
 |       //      throw '...'; | 
 |       //    } | 
 |       return new IfStatement( | 
 |         new StaticInvocation( | 
 |             coreTypes.isSentinelMethod, | 
 |             new Arguments( | 
 |                 <Expression>[createVariableRead()..fileOffset = fileOffset]) | 
 |               ..fileOffset = fileOffset) | 
 |           ..fileOffset = fileOffset, | 
 |         createReturn(createVariableWrite( | 
 |             new VariableGet(parameter)..fileOffset = fileOffset) | 
 |           ..fileOffset = fileOffset), | 
 |         new ExpressionStatement(exception)..fileOffset = fileOffset, | 
 |       )..fileOffset = fileOffset; | 
 |     case IsSetEncoding.useNull: | 
 |       // Generate: | 
 |       // | 
 |       //    if (_#field == null) { | 
 |       //      return _#field = parameter; | 
 |       //    } else { | 
 |       //      throw '...'; | 
 |       //    } | 
 |       return new IfStatement( | 
 |         useNewMethodInvocationEncoding | 
 |             ? (new EqualsNull(createVariableRead()..fileOffset = fileOffset) | 
 |               ..fileOffset = fileOffset) | 
 |             : new MethodInvocation( | 
 |                 createVariableRead()..fileOffset = fileOffset, | 
 |                 equalsName, | 
 |                 new Arguments( | 
 |                     <Expression>[new NullLiteral()..fileOffset = fileOffset]) | 
 |                   ..fileOffset = fileOffset) | 
 |           ..fileOffset = fileOffset, | 
 |         createReturn(createVariableWrite( | 
 |             new VariableGet(parameter)..fileOffset = fileOffset) | 
 |           ..fileOffset = fileOffset), | 
 |         new ExpressionStatement(exception)..fileOffset = fileOffset, | 
 |       )..fileOffset = fileOffset; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding"); | 
 | } | 
 |  | 
 | /// Strategies for encoding whether a late field/local has been initialized. | 
 | enum IsSetEncoding { | 
 |   /// Use a boolean `isSet` field/local. | 
 |   useIsSetField, | 
 |  | 
 |   /// Use `null` as sentinel value to signal an uninitialized field/locals. | 
 |   useNull, | 
 |  | 
 |   /// Use `createSentinel`and `isSentinel` from `dart:_internal` to generate | 
 |   /// and check a sentinel value to signal an uninitialized field/local. | 
 |   useSentinel, | 
 | } | 
 |  | 
 | /// Strategies for encoding of late fields and locals. | 
 | enum IsSetStrategy { | 
 |   /// Always is use an `isSet` field/local to track whether the field/local has | 
 |   /// been initialized. | 
 |   forceUseIsSetField, | 
 |  | 
 |   /// Always use `createSentinel`and `isSentinel` from `dart:_internal` to | 
 |   /// generate and check a sentinel value to signal an uninitialized | 
 |   /// field/local. | 
 |   forceUseSentinel, | 
 |  | 
 |   /// For potentially nullable fields/locals use an `isSet` field/local to track | 
 |   /// whether the field/local has been initialized. Otherwise use `null` as | 
 |   /// sentinel value to signal an uninitialized field/local. | 
 |   /// | 
 |   /// This strategy can only be used with sound null safety mode. In weak mode | 
 |   /// non-nullable can be assigned `null` from legacy code and therefore `null` | 
 |   /// doesn't work as a sentinel. | 
 |   useIsSetFieldOrNull, | 
 |  | 
 |   /// For potentially nullable fields/locals use `createSentinel`and | 
 |   /// `isSentinel` from `dart:_internal` to generate and check a sentinel value | 
 |   /// to signal an uninitialized field/local. Otherwise use `null` as | 
 |   /// sentinel value to signal an uninitialized field/local. | 
 |   useSentinelOrNull, | 
 | } | 
 |  | 
 | IsSetStrategy computeIsSetStrategy(SourceLibraryBuilder libraryBuilder) { | 
 |   IsSetStrategy isSetStrategy = IsSetStrategy.useIsSetFieldOrNull; | 
 |   if (libraryBuilder.loader.target.backendTarget.supportsLateLoweringSentinel) { | 
 |     if (libraryBuilder.loader.nnbdMode != NnbdMode.Strong) { | 
 |       // Non-nullable fields/locals might contain `null` so we always use the | 
 |       // sentinel. | 
 |       isSetStrategy = IsSetStrategy.forceUseSentinel; | 
 |     } else { | 
 |       isSetStrategy = IsSetStrategy.useSentinelOrNull; | 
 |     } | 
 |   } else if (libraryBuilder.loader.nnbdMode != NnbdMode.Strong) { | 
 |     isSetStrategy = IsSetStrategy.forceUseIsSetField; | 
 |   } | 
 |   return isSetStrategy; | 
 | } | 
 |  | 
 | IsSetEncoding computeIsSetEncoding(DartType type, IsSetStrategy isSetStrategy) { | 
 |   switch (isSetStrategy) { | 
 |     case IsSetStrategy.forceUseIsSetField: | 
 |       return IsSetEncoding.useIsSetField; | 
 |     case IsSetStrategy.forceUseSentinel: | 
 |       return IsSetEncoding.useSentinel; | 
 |     case IsSetStrategy.useIsSetFieldOrNull: | 
 |       return type.isPotentiallyNullable | 
 |           ? IsSetEncoding.useIsSetField | 
 |           : IsSetEncoding.useNull; | 
 |     case IsSetStrategy.useSentinelOrNull: | 
 |       return type.isPotentiallyNullable | 
 |           ? IsSetEncoding.useSentinel | 
 |           : IsSetEncoding.useNull; | 
 |   } | 
 |   throw new UnsupportedError("Unexpected IsSetStrategy $isSetStrategy"); | 
 | } | 
 |  | 
 | /// Returns the name used for the variable that holds the value of a late | 
 | /// lowered local by the given [name]. | 
 | String computeLateLocalName(String name) { | 
 |   return '${lateLocalPrefix}$name'; | 
 | } | 
 |  | 
 | /// Returns the name used for the 'isSet' variable of a late lowered local by | 
 | /// the given [name]. | 
 | String computeLateLocalIsSetName(String name) { | 
 |   return '${lateLocalPrefix}${name}${lateIsSetSuffix}'; | 
 | } | 
 |  | 
 | /// Returns the name used for the getter function of a late lowered local by | 
 | /// the given [name]. | 
 | String computeLateLocalGetterName(String name) { | 
 |   return '${lateLocalPrefix}${name}${lateLocalGetterSuffix}'; | 
 | } | 
 |  | 
 | /// Returns the name used for the setter function of a late lowered local by | 
 | /// the given [name]. | 
 | String computeLateLocalSetterName(String name) { | 
 |   return '${lateLocalPrefix}${name}${lateLocalSetterSuffix}'; | 
 | } |