// Copyright (c) 2024, 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.

part of 'fragment.dart';

class SetterFragment implements Fragment, FunctionFragment {
  @override
  final String name;

  final Uri fileUri;
  final int startOffset;
  final int nameOffset;
  final int formalsOffset;
  final int endOffset;
  final bool isTopLevel;
  final List<MetadataBuilder>? metadata;
  final Modifiers modifiers;

  /// The declared return type of this setter.
  ///
  /// If the return type was omitted, this is an [InferableTypeBuilder].
  final TypeBuilder returnType;

  /// The name space for the type parameters available on this setter.
  ///
  /// Initially this is empty, since setters don't have type parameters, but for
  /// extension and extension type instance setters this will include type
  /// parameters cloned from the extension or extension type, respectively.
  final NominalParameterNameSpace typeParameterNameSpace;

  /// The declared type parameters on this setter.
  ///
  /// This is only non-null in erroneous cases since setters don't have type
  /// parameters.
  final List<NominalParameterBuilder>? declaredTypeParameters;

  /// The scope that introduces type parameters on this setter.
  ///
  /// This is based on [typeParameterNameSpace] and initially doesn't introduce
  /// any type parameters, since setters don't have type parameters, but for
  /// extension and extension type instance setters this will include type
  /// parameters cloned from the extension or extension type, respectively.
  final LookupScope typeParameterScope;

  /// The declared formals on this setter.
  final List<FormalParameterBuilder>? declaredFormals;

  final AsyncMarker asyncModifier;
  final String? nativeMethodName;

  SourcePropertyBuilder? _builder;

  late final _SetterEncoding _encoding;

  SetterFragment(
      {required this.name,
      required this.fileUri,
      required this.startOffset,
      required this.nameOffset,
      required this.formalsOffset,
      required this.endOffset,
      required this.isTopLevel,
      required this.metadata,
      required this.modifiers,
      required this.returnType,
      required this.declaredTypeParameters,
      required this.typeParameterNameSpace,
      required this.typeParameterScope,
      required this.declaredFormals,
      required this.asyncModifier,
      required this.nativeMethodName});

  @override
  SourcePropertyBuilder get builder {
    assert(_builder != null, "Builder has not been computed for $this.");
    return _builder!;
  }

  void setBuilder(
      SourcePropertyBuilder value,
      List<NominalParameterBuilder>? typeParameters,
      List<FormalParameterBuilder>? formals) {
    assert(_builder == null, "Builder has already been computed for $this.");
    _builder = value;
    switch (value.declarationBuilder) {
      case null:
      case ClassBuilder():
        _encoding = new _RegularSetterEncoding(this);
      case ExtensionTypeDeclarationBuilder():
        if (modifiers.isStatic) {
          assert(typeParameters == null,
              "Unexpected type parameters on setter: $typeParameters");
          assert(formals == null,
              "Unexpected formal parameters on setter: $formals");
          _encoding = new _ExtensionTypeStaticSetterEncoding(this);
        } else {
          assert(
              formals != null,
              "Unexpected formal parameters on extension type instance getter: "
              "$formals");
          assert(formals!.length == 1,
              "Unexpected formals on extension type instance getter: $formals");
          _encoding = new _ExtensionTypeInstanceSetterEncoding(
              this, typeParameters, formals!.single);
        }
      case ExtensionBuilder():
        if (modifiers.isStatic) {
          assert(typeParameters == null,
              "Unexpected type parameters on setter: $typeParameters");
          assert(formals == null,
              "Unexpected formal parameters on setter: $formals");
          _encoding = new _ExtensionStaticSetterEncoding(this);
        } else {
          assert(
              formals != null,
              "Unexpected formal parameters on extension instance getter: "
              "$formals");
          assert(formals!.length == 1,
              "Unexpected formals on extension instance getter: $formals");
          _encoding = new _ExtensionInstanceSetterEncoding(
              this, typeParameters, formals!.single);
        }
    }
  }

  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
      NameScheme nameScheme, BuildNodesCallback f,
      {required Reference setterReference,
      required List<TypeParameter>? classTypeParameters}) {
    _encoding.buildOutlineNode(libraryBuilder, nameScheme, f,
        setterReference: setterReference,
        isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal,
        classTypeParameters: classTypeParameters);
  }

  void buildOutlineExpressions(
      ClassHierarchy classHierarchy,
      SourceLibraryBuilder libraryBuilder,
      DeclarationBuilder? declarationBuilder,
      LookupScope parentScope,
      Annotatable annotatable,
      {required bool isClassInstanceMember,
      required bool createFileUriExpression}) {
    _encoding.buildOutlineExpressions(
        classHierarchy,
        libraryBuilder,
        declarationBuilder,
        parentScope,
        createBodyBuilderContext(),
        annotatable,
        isClassInstanceMember: isClassInstanceMember,
        createFileUriExpression: createFileUriExpression);
  }

  void ensureTypes(
      ClassMembersBuilder membersBuilder,
      SourceClassBuilder enclosingClassBuilder,
      Set<ClassMember>? setterOverrideDependencies) {
    if (setterOverrideDependencies != null) {
      membersBuilder.inferSetterType(
          enclosingClassBuilder, declaredFormals, setterOverrideDependencies,
          name: name,
          fileUri: fileUri,
          nameOffset: nameOffset,
          nameLength: name.length);
    }
    _encoding.ensureTypes(
        enclosingClassBuilder.libraryBuilder, membersBuilder.hierarchyBuilder);
  }

  void checkTypes(
      SourceLibraryBuilder libraryBuilder, TypeEnvironment typeEnvironment,
      {required bool isAbstract, required bool isExternal}) {
    _encoding.checkTypes(libraryBuilder, typeEnvironment,
        isAbstract: isAbstract, isExternal: isExternal);
  }

  void checkVariance(
      SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
    _encoding.checkVariance(sourceClassBuilder, typeEnvironment);
  }

  int computeDefaultTypes(ComputeDefaultTypeContext context) {
    return _encoding.computeDefaultTypes(context);
  }

  Procedure get writeTarget => _encoding.writeTarget;

  // Coverage-ignore(suite): Not run.
  List<NominalParameterBuilder>? get typeParametersForTesting =>
      _encoding.typeParametersForTesting;

  // Coverage-ignore(suite): Not run.
  List<FormalParameterBuilder>? get formalsForTesting =>
      _encoding.formalsForTesting;

  @override
  FunctionBodyBuildingContext createFunctionBodyBuildingContext() {
    return new _SetterBodyBuildingContext(this);
  }

  BodyBuilderContext createBodyBuilderContext() {
    return new _SetterFragmentBodyBuilderContext(
        this, builder.libraryBuilder, builder.declarationBuilder,
        isDeclarationInstanceMember: builder.isDeclarationInstanceMember);
  }

  void becomeNative(SourceLoader loader) {
    _encoding.becomeNative(loader);
  }

  @override
  String toString() => '$runtimeType($name,$fileUri,$nameOffset)';
}

class _SetterBodyBuildingContext implements FunctionBodyBuildingContext {
  SetterFragment _fragment;

  _SetterBodyBuildingContext(this._fragment);

  @override
  MemberKind get memberKind => _fragment.isTopLevel
      ? MemberKind.TopLevelMethod
      : (_fragment.modifiers.isStatic
          ? MemberKind.StaticMethod
          : MemberKind.NonStaticMethod);

  @override
  bool get shouldBuild => true;

  @override
  LocalScope computeFormalParameterScope(LookupScope typeParameterScope) {
    return _fragment._encoding.createFormalParameterScope(typeParameterScope);
  }

  @override
  LookupScope get typeParameterScope {
    return _fragment.typeParameterScope;
  }

  @override
  BodyBuilderContext createBodyBuilderContext() {
    return _fragment.createBodyBuilderContext();
  }

  @override
  InferenceDataForTesting? get inferenceDataForTesting => _fragment
      .builder
      .dataForTesting
      // Coverage-ignore(suite): Not run.
      ?.inferenceData;

  @override
  List<TypeParameter>? get thisTypeParameters =>
      _fragment._encoding.thisTypeParameters;

  @override
  VariableDeclaration? get thisVariable => _fragment._encoding.thisVariable;
}

sealed class _SetterEncoding {
  List<TypeParameter>? get thisTypeParameters;
  VariableDeclaration? get thisVariable;
  FunctionNode get function;
  Procedure get writeTarget;

  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
      NameScheme nameScheme, BuildNodesCallback f,
      {required Reference setterReference,
      required bool isAbstractOrExternal,
      required List<TypeParameter>? classTypeParameters});

  void buildOutlineExpressions(
      ClassHierarchy classHierarchy,
      SourceLibraryBuilder libraryBuilder,
      DeclarationBuilder? declarationBuilder,
      LookupScope parentScope,
      BodyBuilderContext bodyBuilderContext,
      Annotatable annotatable,
      {required bool isClassInstanceMember,
      required bool createFileUriExpression});

  LocalScope createFormalParameterScope(LookupScope typeParameterScope);

  int computeDefaultTypes(ComputeDefaultTypeContext context);

  void ensureTypes(
      SourceLibraryBuilder libraryBuilder, ClassHierarchyBase hierarchy);

  void becomeNative(SourceLoader loader);

  List<FormalParameterBuilder>? get formals;

  VariableDeclaration getFormalParameter(int index);

  void checkTypes(
      SourceLibraryBuilder libraryBuilder, TypeEnvironment typeEnvironment,
      {required bool isAbstract, required bool isExternal});

  void checkVariance(
      SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment);

  List<NominalParameterBuilder>? get typeParametersForTesting;

  List<FormalParameterBuilder>? get formalsForTesting;
}

mixin _DirectSetterEncodingMixin implements _SetterEncoding {
  SetterFragment get _fragment;

  Procedure? _procedure;

  @override
  VariableDeclaration? get thisVariable => null;

  @override
  List<TypeParameter>? get thisTypeParameters => null;

  @override
  LocalScope createFormalParameterScope(LookupScope parent) {
    Map<String, Builder> local = <String, Builder>{};
    List<FormalParameterBuilder>? formals = _fragment.declaredFormals;
    if (formals != null) {
      for (FormalParameterBuilder formal in formals) {
        if (formal.isWildcard) {
          continue;
        }
        local[formal.name] = formal;
      }
    }
    return new FormalParameterScope(local: local, parent: parent);
  }

  @override
  List<FormalParameterBuilder>? get formals => _fragment.declaredFormals;

  @override
  VariableDeclaration getFormalParameter(int index) =>
      _fragment.declaredFormals![index].variable!;

  BuiltMemberKind get _builtMemberKind;

  bool get _isExtensionMember;

  bool get _isExtensionTypeMember;

  @override
  FunctionNode get function => _procedure!.function;

  @override
  Procedure get writeTarget => _procedure!;

  @override
  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
      NameScheme nameScheme, BuildNodesCallback f,
      {required Reference setterReference,
      required bool isAbstractOrExternal,
      List<TypeParameter>? classTypeParameters}) {
    FunctionNode function = new FunctionNode(
        isAbstractOrExternal ? null : new EmptyStatement(),
        asyncMarker: _fragment.asyncModifier)
      ..fileOffset = _fragment.formalsOffset
      ..fileEndOffset = _fragment.endOffset;
    buildTypeParametersAndFormals(libraryBuilder, function,
        _fragment.declaredTypeParameters, _fragment.declaredFormals,
        classTypeParameters: classTypeParameters, supportsTypeParameters: true);
    if (_fragment.returnType is! InferableTypeBuilder) {
      function.returnType =
          _fragment.returnType.build(libraryBuilder, TypeUse.returnType);
    }
    if (_fragment.declaredFormals?.length != 1 ||
        _fragment.declaredFormals![0].isOptionalPositional) {
      // Replace illegal parameters by single dummy parameter.
      // Do this after building the parameters, since the diet listener
      // assumes that parameters are built, even if illegal in number.
      VariableDeclaration parameter = new VariableDeclarationImpl("#synthetic");
      function.positionalParameters.clear();
      function.positionalParameters.add(parameter);
      parameter.parent = function;
      function.namedParameters.clear();
      function.requiredParameterCount = 1;
    }
    MemberName memberName =
        nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name);
    Procedure procedure = _procedure = new Procedure(
        memberName.name, ProcedureKind.Setter, function,
        reference: setterReference, fileUri: _fragment.fileUri)
      ..fileStartOffset = _fragment.startOffset
      ..fileOffset = _fragment.nameOffset
      ..fileEndOffset = _fragment.endOffset
      ..isAbstract = _fragment.modifiers.isAbstract
      ..isExternal = _fragment.modifiers.isExternal
      ..isConst = _fragment.modifiers.isConst
      ..isStatic = _fragment.modifiers.isStatic
      ..isExtensionMember = _isExtensionMember
      ..isExtensionTypeMember = _isExtensionTypeMember;
    memberName.attachMember(procedure);

    f(kind: _builtMemberKind, member: procedure);
  }

  @override
  void buildOutlineExpressions(
      ClassHierarchy classHierarchy,
      SourceLibraryBuilder libraryBuilder,
      DeclarationBuilder? declarationBuilder,
      LookupScope parentScope,
      BodyBuilderContext bodyBuilderContext,
      Annotatable annotatable,
      {required bool isClassInstanceMember,
      required bool createFileUriExpression}) {
    _buildMetadataForOutlineExpressions(libraryBuilder, parentScope,
        bodyBuilderContext, annotatable, _fragment.metadata,
        fileUri: _fragment.fileUri,
        createFileUriExpression: createFileUriExpression);

    _buildTypeParametersForOutlineExpressions(
        classHierarchy,
        libraryBuilder,
        bodyBuilderContext,
        _fragment.typeParameterScope,
        _fragment.declaredTypeParameters);
    _buildFormalsForOutlineExpressions(
        libraryBuilder, declarationBuilder, _fragment.declaredFormals,
        isClassInstanceMember: isClassInstanceMember);
  }

  @override
  void becomeNative(SourceLoader loader) {
    loader.addNativeAnnotation(_procedure!, _fragment.nativeMethodName!);
  }

  @override
  void checkTypes(
      SourceLibraryBuilder libraryBuilder, TypeEnvironment typeEnvironment,
      {required bool isAbstract, required bool isExternal}) {
    List<TypeParameterBuilder>? typeParameters =
        _fragment.declaredTypeParameters;
    // Coverage-ignore(suite): Not run.
    if (typeParameters != null && typeParameters.isNotEmpty) {
      libraryBuilder.checkTypeParameterDependencies(typeParameters);
    }
    libraryBuilder.checkInitializersInFormals(
        _fragment.declaredFormals, typeEnvironment,
        isAbstract: isAbstract, isExternal: isExternal);
  }

  @override
  void checkVariance(
      SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
    sourceClassBuilder.checkVarianceInTypeParameters(
        typeEnvironment, _fragment.declaredTypeParameters);
    sourceClassBuilder.checkVarianceInFormals(
        typeEnvironment, _fragment.declaredFormals);
    sourceClassBuilder.checkVarianceInReturnType(
        typeEnvironment, function.returnType,
        fileOffset: _fragment.nameOffset, fileUri: _fragment.fileUri);
  }

  @override
  int computeDefaultTypes(ComputeDefaultTypeContext context) {
    bool hasErrors = context.reportSimplicityIssuesForTypeParameters(
        _fragment.declaredTypeParameters);
    context.reportGenericFunctionTypesForFormals(_fragment.declaredFormals);
    if (_fragment.returnType is! OmittedTypeBuilder) {
      hasErrors |=
          context.reportInboundReferenceIssuesForType(_fragment.returnType);
      context.recursivelyReportGenericFunctionTypesAsBoundsForType(
          _fragment.returnType);
    }
    return context.computeDefaultTypesForVariables(
        _fragment.declaredTypeParameters,
        inErrorRecovery: hasErrors);
  }

  @override
  void ensureTypes(
      SourceLibraryBuilder libraryBuilder, ClassHierarchyBase hierarchy) {
    _fragment.returnType
        .build(libraryBuilder, TypeUse.returnType, hierarchy: hierarchy);
    List<FormalParameterBuilder>? declaredFormals = _fragment.declaredFormals;
    if (declaredFormals != null) {
      for (FormalParameterBuilder formal in declaredFormals) {
        formal.type
            .build(libraryBuilder, TypeUse.parameterType, hierarchy: hierarchy);
      }
    }
  }

  @override
  // Coverage-ignore(suite): Not run.
  List<NominalParameterBuilder>? get typeParametersForTesting =>
      _fragment.declaredTypeParameters;

  @override
  // Coverage-ignore(suite): Not run.
  List<FormalParameterBuilder>? get formalsForTesting =>
      _fragment.declaredFormals;
}

class _RegularSetterEncoding extends _SetterEncoding
    with _DirectSetterEncodingMixin {
  @override
  final SetterFragment _fragment;

  _RegularSetterEncoding(this._fragment);

  @override
  BuiltMemberKind get _builtMemberKind => BuiltMemberKind.Method;

  @override
  bool get _isExtensionMember => false;

  @override
  bool get _isExtensionTypeMember => false;
}

class _ExtensionStaticSetterEncoding extends _SetterEncoding
    with _DirectSetterEncodingMixin {
  @override
  final SetterFragment _fragment;

  _ExtensionStaticSetterEncoding(this._fragment);

  @override
  BuiltMemberKind get _builtMemberKind => BuiltMemberKind.ExtensionSetter;

  @override
  bool get _isExtensionMember => true;

  @override
  bool get _isExtensionTypeMember => false;
}

class _ExtensionTypeStaticSetterEncoding extends _SetterEncoding
    with _DirectSetterEncodingMixin {
  @override
  final SetterFragment _fragment;

  _ExtensionTypeStaticSetterEncoding(this._fragment);

  @override
  BuiltMemberKind get _builtMemberKind => BuiltMemberKind.ExtensionTypeSetter;

  @override
  bool get _isExtensionMember => false;

  @override
  bool get _isExtensionTypeMember => true;
}

mixin _ExtensionInstanceSetterEncodingMixin implements _SetterEncoding {
  SetterFragment get _fragment;

  Procedure? _procedure;

  List<NominalParameterBuilder>? get _clonedDeclarationTypeParameters;

  FormalParameterBuilder get _thisFormal;

  @override
  List<TypeParameter>? get thisTypeParameters =>
      _clonedDeclarationTypeParameters != null ? function.typeParameters : null;

  @override
  VariableDeclaration? get thisVariable => _thisFormal.variable!;

  BuiltMemberKind get _builtMemberKind;

  bool get _isExtensionMember;

  bool get _isExtensionTypeMember;

  @override
  FunctionNode get function => _procedure!.function;

  @override
  Procedure get writeTarget => _procedure!;

  @override
  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
      NameScheme nameScheme, BuildNodesCallback f,
      {required Reference setterReference,
      required bool isAbstractOrExternal,
      required List<TypeParameter>? classTypeParameters}) {
    List<TypeParameter>? typeParameters;
    if (_clonedDeclarationTypeParameters != null) {
      typeParameters = [];
      // TODO(johnniwinther): Ambivalent analyzer. `!` seems to be both required
      // and unnecessary.
      // ignore: unnecessary_non_null_assertion
      for (NominalParameterBuilder t in _clonedDeclarationTypeParameters!) {
        typeParameters.add(t.parameter);
      }
    }
    FunctionNode function = new FunctionNode(
        isAbstractOrExternal ? null : new EmptyStatement(),
        typeParameters: typeParameters,
        positionalParameters: [_thisFormal.build(libraryBuilder)],
        asyncMarker: _fragment.asyncModifier)
      ..fileOffset = _fragment.formalsOffset
      ..fileEndOffset = _fragment.endOffset;
    buildTypeParametersAndFormals(libraryBuilder, function,
        _fragment.declaredTypeParameters, _fragment.declaredFormals,
        classTypeParameters: classTypeParameters, supportsTypeParameters: true);
    // TODO(johnniwinther): We should have a consistent normalization strategy.
    // We ensure that setters have 1 parameter, but for getters we include all
    // declared parameters.
    if ((_fragment.declaredFormals?.length != 1 ||
        _fragment.declaredFormals![0].isOptionalPositional)) {
      // Replace illegal parameters by single dummy parameter (after #this).
      // Do this after building the parameters, since the diet listener
      // assumes that parameters are built, even if illegal in number.
      VariableDeclaration thisParameter = function.positionalParameters[0];
      VariableDeclaration parameter = new VariableDeclarationImpl("#synthetic");
      function.positionalParameters.clear();
      function.positionalParameters.add(thisParameter);
      function.positionalParameters.add(parameter);
      parameter.parent = function;
      function.namedParameters.clear();
      function.requiredParameterCount = 2;
    }
    if (_fragment.returnType is! InferableTypeBuilder) {
      function.returnType =
          _fragment.returnType.build(libraryBuilder, TypeUse.returnType);
    }

    MemberName memberName =
        nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name);
    Procedure procedure = _procedure = new Procedure(
        memberName.name, ProcedureKind.Method, function,
        reference: setterReference, fileUri: _fragment.fileUri)
      ..fileStartOffset = _fragment.startOffset
      ..fileOffset = _fragment.nameOffset
      ..fileEndOffset = _fragment.endOffset
      ..isAbstract = _fragment.modifiers.isAbstract
      ..isExternal = _fragment.modifiers.isExternal
      ..isConst = _fragment.modifiers.isConst
      ..isStatic = true
      ..isExtensionMember = _isExtensionMember
      ..isExtensionTypeMember = _isExtensionTypeMember;
    memberName.attachMember(procedure);

    f(kind: _builtMemberKind, member: procedure);
  }

  @override
  void buildOutlineExpressions(
      ClassHierarchy classHierarchy,
      SourceLibraryBuilder libraryBuilder,
      DeclarationBuilder? declarationBuilder,
      LookupScope parentScope,
      BodyBuilderContext bodyBuilderContext,
      Annotatable annotatable,
      {required bool isClassInstanceMember,
      required bool createFileUriExpression}) {
    _buildMetadataForOutlineExpressions(libraryBuilder, parentScope,
        bodyBuilderContext, annotatable, _fragment.metadata,
        fileUri: _fragment.fileUri,
        createFileUriExpression: createFileUriExpression);

    _buildTypeParametersForOutlineExpressions(
        classHierarchy,
        libraryBuilder,
        bodyBuilderContext,
        _fragment.typeParameterScope,
        _fragment.declaredTypeParameters);
    _buildFormalsForOutlineExpressions(
        libraryBuilder, declarationBuilder, _fragment.declaredFormals,
        isClassInstanceMember: isClassInstanceMember);

    _buildTypeParametersForOutlineExpressions(
        classHierarchy,
        libraryBuilder,
        bodyBuilderContext,
        _fragment.typeParameterScope,
        _clonedDeclarationTypeParameters);
    _buildFormalForOutlineExpressions(
        libraryBuilder, declarationBuilder, _thisFormal,
        isClassInstanceMember: isClassInstanceMember);
  }

  @override
  // Coverage-ignore(suite): Not run.
  void becomeNative(SourceLoader loader) {
    loader.addNativeAnnotation(_procedure!, _fragment.nativeMethodName!);
  }

  @override
  void checkTypes(
      SourceLibraryBuilder libraryBuilder, TypeEnvironment typeEnvironment,
      {required bool isAbstract, required bool isExternal}) {
    List<TypeParameterBuilder>? typeParameters =
        _fragment.declaredTypeParameters;
    // Coverage-ignore(suite): Not run.
    if (typeParameters != null && typeParameters.isNotEmpty) {
      libraryBuilder.checkTypeParameterDependencies(typeParameters);
    }
    libraryBuilder.checkInitializersInFormals(
        _fragment.declaredFormals, typeEnvironment,
        isAbstract: isAbstract, isExternal: isExternal);
  }

  @override
  // Coverage-ignore(suite): Not run.
  void checkVariance(
      SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
    sourceClassBuilder.checkVarianceInTypeParameters(
        typeEnvironment, _fragment.declaredTypeParameters);
    sourceClassBuilder.checkVarianceInFormals(
        typeEnvironment, _fragment.declaredFormals);
    sourceClassBuilder.checkVarianceInReturnType(
        typeEnvironment, function.returnType,
        fileOffset: _fragment.nameOffset, fileUri: _fragment.fileUri);
  }

  @override
  LocalScope createFormalParameterScope(LookupScope parent) {
    Map<String, Builder> local = <String, Builder>{};

    assert(!_thisFormal.isWildcard);
    local[_thisFormal.name] = _thisFormal;

    List<FormalParameterBuilder>? formals = _fragment.declaredFormals;
    if (formals != null) {
      for (FormalParameterBuilder formal in formals) {
        if (formal.isWildcard) {
          continue;
        }
        local[formal.name] = formal;
      }
    }
    return new FormalParameterScope(local: local, parent: parent);
  }

  @override
  int computeDefaultTypes(ComputeDefaultTypeContext context) {
    bool hasErrors = context.reportSimplicityIssuesForTypeParameters(
        _fragment.declaredTypeParameters);
    context.reportGenericFunctionTypesForFormals(_fragment.declaredFormals);
    if (_fragment.returnType is! OmittedTypeBuilder) {
      hasErrors |=
          context.reportInboundReferenceIssuesForType(_fragment.returnType);
      context.recursivelyReportGenericFunctionTypesAsBoundsForType(
          _fragment.returnType);
    }
    int count = context.computeDefaultTypesForVariables(
        _fragment.declaredTypeParameters,
        inErrorRecovery: hasErrors);
    count += context.computeDefaultTypesForVariables(
        _clonedDeclarationTypeParameters,
        inErrorRecovery: hasErrors);
    return count;
  }

  @override
  // Coverage-ignore(suite): Not run.
  void ensureTypes(
      SourceLibraryBuilder libraryBuilder, ClassHierarchyBase hierarchy) {
    _fragment.returnType
        .build(libraryBuilder, TypeUse.fieldType, hierarchy: hierarchy);
    _thisFormal.type
        .build(libraryBuilder, TypeUse.parameterType, hierarchy: hierarchy);
    List<FormalParameterBuilder>? declaredFormals = _fragment.declaredFormals;
    if (declaredFormals != null) {
      for (FormalParameterBuilder formal in declaredFormals) {
        formal.type
            .build(libraryBuilder, TypeUse.parameterType, hierarchy: hierarchy);
      }
    }
  }

  @override
  List<FormalParameterBuilder>? get formals =>
      [_thisFormal, ...?_fragment.declaredFormals];

  @override
  VariableDeclaration getFormalParameter(int index) =>
      _fragment.declaredFormals![index].variable!;

  @override
  // Coverage-ignore(suite): Not run.
  List<NominalParameterBuilder>? get typeParametersForTesting =>
      _clonedDeclarationTypeParameters != null ||
              _fragment.declaredTypeParameters != null
          ? [
              ...?_clonedDeclarationTypeParameters,
              ...?_fragment.declaredTypeParameters
            ]
          : null;

  @override
  // Coverage-ignore(suite): Not run.
  List<FormalParameterBuilder>? get formalsForTesting =>
      [_thisFormal, ...?_fragment.declaredFormals];
}

class _ExtensionInstanceSetterEncoding extends _SetterEncoding
    with _ExtensionInstanceSetterEncodingMixin {
  @override
  final SetterFragment _fragment;

  @override
  final List<NominalParameterBuilder>? _clonedDeclarationTypeParameters;

  @override
  final FormalParameterBuilder _thisFormal;

  _ExtensionInstanceSetterEncoding(
      this._fragment, this._clonedDeclarationTypeParameters, this._thisFormal);

  @override
  BuiltMemberKind get _builtMemberKind => BuiltMemberKind.ExtensionSetter;

  @override
  bool get _isExtensionMember => true;

  @override
  bool get _isExtensionTypeMember => false;
}

class _ExtensionTypeInstanceSetterEncoding extends _SetterEncoding
    with _ExtensionInstanceSetterEncodingMixin {
  @override
  final SetterFragment _fragment;

  @override
  final List<NominalParameterBuilder>? _clonedDeclarationTypeParameters;

  @override
  final FormalParameterBuilder _thisFormal;

  _ExtensionTypeInstanceSetterEncoding(
      this._fragment, this._clonedDeclarationTypeParameters, this._thisFormal);

  @override
  BuiltMemberKind get _builtMemberKind => BuiltMemberKind.ExtensionTypeSetter;

  @override
  bool get _isExtensionMember => false;

  @override
  bool get _isExtensionTypeMember => true;
}

class _SetterFragmentBodyBuilderContext extends BodyBuilderContext {
  final SetterFragment _fragment;

  _SetterFragmentBodyBuilderContext(
      this._fragment,
      SourceLibraryBuilder libraryBuilder,
      DeclarationBuilder? declarationBuilder,
      {required bool isDeclarationInstanceMember})
      : super(libraryBuilder, declarationBuilder,
            isDeclarationInstanceMember: isDeclarationInstanceMember);

  @override
  bool get isSetter => true;

  @override
  LocalScope computeFormalParameterInitializerScope(LocalScope parent) {
    /// Initializer formals or super parameters cannot occur in getters so
    /// we don't need to create a new scope.
    return parent;
  }

  @override
  FunctionNode get function => _fragment._encoding.function;

  @override
  void setAsyncModifier(AsyncMarker asyncModifier) {
    assert(
        asyncModifier == _fragment.asyncModifier,
        "Unexpected change in async modifier on $_fragment from "
        "${_fragment.asyncModifier} to $asyncModifier.");
  }

  @override
  int get memberNameOffset => _fragment.nameOffset;

  @override
  int get memberNameLength => _fragment.name.length;

  @override
  DartType get returnTypeContext {
    final bool isReturnTypeUndeclared =
        _fragment.returnType is OmittedTypeBuilder &&
            // Coverage-ignore(suite): Not run.
            function.returnType is DynamicType;
    return isReturnTypeUndeclared ? const UnknownType() : function.returnType;
  }

  @override
  TypeBuilder get returnType => _fragment.returnType;

  @override
  void setBody(Statement body) {
    function.body = body..parent = function;
  }

  @override
  void registerSuperCall() {
    // TODO(johnniwinther): This should be set on the member built from this
    // fragment and copied to the origin if necessary.
    _fragment.builder.writeTarget!.transformerFlags |=
        TransformerFlag.superCalls;
  }

  @override
  List<FormalParameterBuilder>? get formals => _fragment._encoding.formals;

  @override
  VariableDeclaration getFormalParameter(int index) =>
      _fragment._encoding.getFormalParameter(index);

  @override
  VariableDeclaration? getTearOffParameter(int index) => null;

  @override
  AugmentSuperTarget? get augmentSuperTarget {
    if (_fragment.builder.isAugmentation) {
      return _fragment.builder.augmentSuperTarget;
    }
    return null;
  }
}
