// 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.
library kernel.transformations.mixin_full_resolution;

import '../ast.dart';
import '../class_hierarchy.dart';
import '../clone.dart';
import '../core_types.dart';
import '../target/targets.dart' show Target;
import '../type_algebra.dart';

void transformLibraries(Target targetInfo, CoreTypes coreTypes,
    ClassHierarchy hierarchy, List<Library> libraries,
    {bool doSuperResolution: true}) {
  new MixinFullResolution(targetInfo, coreTypes, hierarchy,
          doSuperResolution: doSuperResolution)
      .transform(libraries);
}

/// Replaces all mixin applications with regular classes, cloning all fields
/// and procedures from the mixed-in class, cloning all constructors from the
/// base class.
///
/// When [doSuperResolution] constructor parameter is [true], super calls
/// (as well as super initializer invocations) are also resolved to their
/// targets in this pass.
class MixinFullResolution {
  final Target targetInfo;
  final CoreTypes coreTypes;

  /// The [ClassHierarchy] that should be used after applying this transformer.
  /// If any class was updated, in general we need to create a new
  /// [ClassHierarchy] instance, with new dispatch targets; or at least let
  /// the existing instance know that some of its dispatch tables are not
  /// valid anymore.
  ClassHierarchy hierarchy;

  // This enables `super` resolution transformation, which is not compatible
  // with Dart VM's requirements around incremental compilation and has been
  // moved to Dart VM itself.
  final bool doSuperResolution;

  MixinFullResolution(this.targetInfo, this.coreTypes, this.hierarchy,
      {this.doSuperResolution: true});

  /// Transform the given new [libraries].  It is expected that all other
  /// libraries have already been transformed.
  void transform(List<Library> libraries) {
    if (libraries.isEmpty) return;

    var transformedClasses = new Set<Class>();

    // Desugar all mixin application classes by copying in fields/methods from
    // the mixin and constructors from the base class.
    var processedClasses = new Set<Class>();
    for (var library in libraries) {
      if (library.isExternal) continue;

      for (var class_ in library.classes) {
        transformClass(libraries, processedClasses, transformedClasses, class_);
      }
    }

    // We might need to update the class hierarchy.
    hierarchy =
        hierarchy.applyMemberChanges(transformedClasses, findDescendants: true);

    if (!doSuperResolution) {
      return;
    }
    // Resolve all super call expressions and super initializers.
    for (var library in libraries) {
      if (library.isExternal) continue;

      for (var class_ in library.classes) {
        for (var procedure in class_.procedures) {
          if (procedure.containsSuperCalls) {
            new SuperCallResolutionTransformer(
                    hierarchy, coreTypes, class_.superclass, targetInfo)
                .visit(procedure);
          }
        }
      }
    }
  }

  transformClass(
      List<Library> librariesToBeTransformed,
      Set<Class> processedClasses,
      Set<Class> transformedClasses,
      Class class_) {
    // If this class was already handled then so were all classes up to the
    // [Object] class.
    if (!processedClasses.add(class_)) return;

    if (!librariesToBeTransformed.contains(class_.enclosingLibrary) &&
        class_.enclosingLibrary.importUri?.scheme == "dart") {
      // If we're not asked to transform the platform libraries then we expect
      // that they will be already transformed.
      return;
    }

    // Ensure super classes have been transformed before this class.
    if (class_.superclass != null &&
        class_.superclass.level.index >= ClassLevel.Mixin.index) {
      transformClass(librariesToBeTransformed, processedClasses,
          transformedClasses, class_.superclass);
    }

    // If this is not a mixin application we don't need to make forwarding
    // constructors in this class.
    if (!class_.isMixinApplication) return;
    assert(librariesToBeTransformed.contains(class_.enclosingLibrary));

    if (class_.mixedInClass.level.index < ClassLevel.Mixin.index) {
      throw new Exception(
          'Class "${class_.name}" mixes in "${class_.mixedInClass.name}" from'
          ' an external library.  Did you forget --link?');
    }

    transformedClasses.add(class_);

    // Clone fields and methods from the mixin class.
    var substitution = getSubstitutionMap(class_.mixedInType);
    var cloner = new CloneVisitor(typeSubstitution: substitution);

    // When we copy a field from the mixed in class, we remove any
    // forwarding-stub getters/setters from the superclass, but copy their
    // covariance-bits onto the new field.
    var nonSetters = <Name, Procedure>{};
    var setters = <Name, Procedure>{};
    for (var procedure in class_.procedures) {
      if (procedure.isSetter) {
        setters[procedure.name] = procedure;
      } else {
        nonSetters[procedure.name] = procedure;
      }
    }
    for (var field in class_.mixin.fields) {
      Field clone = cloner.clone(field);
      Procedure setter = setters[field.name];
      if (setter != null) {
        setters.remove(field.name);
        VariableDeclaration parameter =
            setter.function.positionalParameters.first;
        clone.isGenericCovariantImpl = parameter.isGenericCovariantImpl;
      }
      nonSetters.remove(field.name);
      class_.addMember(clone);
    }
    class_.procedures.clear();
    class_.procedures..addAll(nonSetters.values)..addAll(setters.values);

    // Existing procedures in the class should only be forwarding stubs.
    // Replace them with methods from the mixin class if they have the same
    // name, but keep their parameter flags.
    int originalLength = class_.procedures.length;
    outer:
    for (var procedure in class_.mixin.procedures) {
      // Forwarding stubs in the mixin class are used when calling through the
      // mixin class's interface, not when calling through the mixin
      // application.  They should not be copied.
      if (procedure.isForwardingStub) continue;

      // Factory constructors are not cloned.
      if (procedure.isFactory) continue;

      // NoSuchMethod forwarders aren't cloned.
      if (procedure.isNoSuchMethodForwarder) continue;

      Procedure clone = cloner.clone(procedure);
      // Linear search for a forwarding stub with the same name.
      for (int i = 0; i < originalLength; ++i) {
        var originalProcedure = class_.procedures[i];
        if (originalProcedure.name == clone.name &&
            originalProcedure.kind == clone.kind) {
          FunctionNode src = originalProcedure.function;
          FunctionNode dst = clone.function;

          if (src.positionalParameters.length !=
                  dst.positionalParameters.length ||
              src.namedParameters.length != dst.namedParameters.length) {
            // A compile time error has already occured, but don't crash below,
            // and don't add several procedures with the same name to the class.
            continue outer;
          }

          assert(src.typeParameters.length == dst.typeParameters.length);
          for (int j = 0; j < src.typeParameters.length; ++j) {
            dst.typeParameters[j].flags = src.typeParameters[i].flags;
          }
          for (int j = 0; j < src.positionalParameters.length; ++j) {
            dst.positionalParameters[j].flags =
                src.positionalParameters[j].flags;
          }
          // TODO(kernel team): The named parameters are not sorted,
          // this might not be correct.
          for (int j = 0; j < src.namedParameters.length; ++j) {
            dst.namedParameters[j].flags = src.namedParameters[j].flags;
          }

          class_.procedures[i] = clone;
          continue outer;
        }
      }
      class_.addMember(clone);
    }
    assert(class_.constructors.isNotEmpty);

    // This class implements the mixin type. Also, backends rely on the fact
    // that eliminated mixin is appended into the end of interfaces list.
    class_.implementedTypes.add(class_.mixedInType);

    // This class is now a normal class.
    class_.mixedInType = null;

    // Leave breadcrumbs for backends (e.g. for dart:mirrors implementation).
    class_.isEliminatedMixin = true;
  }
}

class SuperCallResolutionTransformer extends Transformer {
  final ClassHierarchy hierarchy;
  final CoreTypes coreTypes;
  final Class lookupClass;
  final Target targetInfo;

  SuperCallResolutionTransformer(
      this.hierarchy, this.coreTypes, this.lookupClass, this.targetInfo);

  TreeNode visit(TreeNode node) => node.accept(this);

  visitSuperPropertyGet(SuperPropertyGet node) {
    Member target = hierarchy.getDispatchTarget(lookupClass, node.name);
    if (target != null) {
      return new DirectPropertyGet(new ThisExpression(), target)
        ..fileOffset = node.fileOffset;
    } else {
      return _callNoSuchMethod(node.name.name, new Arguments.empty(), node,
          isGetter: true, isSuper: true);
    }
  }

  visitSuperPropertySet(SuperPropertySet node) {
    Member target =
        hierarchy.getDispatchTarget(lookupClass, node.name, setter: true);
    if (target != null) {
      return new DirectPropertySet(
          new ThisExpression(), target, visit(node.value))
        ..fileOffset = node.fileOffset;
    } else {
      // Call has to return right-hand-side.
      VariableDeclaration rightHandSide =
          new VariableDeclaration.forValue(visit(node.value));
      Expression result = _callNoSuchMethod(
          node.name.name, new Arguments([new VariableGet(rightHandSide)]), node,
          isSetter: true, isSuper: true);
      VariableDeclaration call = new VariableDeclaration.forValue(result);
      return new Let(
          rightHandSide, new Let(call, new VariableGet(rightHandSide)));
    }
  }

  visitSuperMethodInvocation(SuperMethodInvocation node) {
    Member target = hierarchy.getDispatchTarget(lookupClass, node.name);
    Arguments visitedArguments = visit(node.arguments);
    if (target is Procedure &&
        !target.isAccessor &&
        _callIsLegal(target.function, visitedArguments)) {
      return new DirectMethodInvocation(
          new ThisExpression(), target, visitedArguments)
        ..fileOffset = node.fileOffset;
    } else if (target == null || (target is Procedure && !target.isAccessor)) {
      // Target not found at all, or call was illegal.
      return _callNoSuchMethod(node.name.name, visitedArguments, node,
          isSuper: true);
    } else {
      return new MethodInvocation(
          new DirectPropertyGet(new ThisExpression(), target),
          new Name('call'),
          visitedArguments)
        ..fileOffset = node.fileOffset;
    }
  }

  /// Create a call to no such method.
  Expression _callNoSuchMethod(
      String methodName, Arguments methodArguments, TreeNode node,
      {isSuper: false, isGetter: false, isSetter: false}) {
    Member noSuchMethod =
        hierarchy.getDispatchTarget(lookupClass, new Name("noSuchMethod"));
    String methodNameUsed = (isGetter)
        ? "get:$methodName"
        : (isSetter) ? "set:$methodName" : methodName;
    if (noSuchMethod != null &&
        noSuchMethod.function.positionalParameters.length == 1 &&
        noSuchMethod.function.namedParameters.isEmpty) {
      // We have a correct noSuchMethod method.
      ConstructorInvocation invocation = _createInvocation(
          methodNameUsed, methodArguments, isSuper, new ThisExpression());
      return new DirectMethodInvocation(
          new ThisExpression(), noSuchMethod, new Arguments([invocation]))
        ..fileOffset = node.fileOffset;
    } else {
      // Incorrect noSuchMethod method: Call noSuchMethod on Object
      // with Invocation of noSuchMethod as the method that did not exist.
      noSuchMethod = hierarchy.getDispatchTarget(
          coreTypes.objectClass, new Name("noSuchMethod"));
      ConstructorInvocation invocation = _createInvocation(
          methodNameUsed, methodArguments, isSuper, new ThisExpression());
      ConstructorInvocation invocationPrime = _createInvocation("noSuchMethod",
          new Arguments([invocation]), false, new ThisExpression());
      return new DirectMethodInvocation(
          new ThisExpression(), noSuchMethod, new Arguments([invocationPrime]))
        ..fileOffset = node.fileOffset;
    }
  }

  /// Creates an "new _InvocationMirror(...)" invocation.
  ConstructorInvocation _createInvocation(String methodName,
      Arguments callArguments, bool isSuperInvocation, Expression receiver) {
    return targetInfo.instantiateInvocation(
        coreTypes, receiver, methodName, callArguments, -1, isSuperInvocation);
  }

  /// Check that a call to the targetFunction is legal given the arguments.
  ///
  /// I.e. check that the number of positional parameters and the names of the
  /// given named parameters represents a valid call to the function.
  bool _callIsLegal(FunctionNode targetFunction, Arguments arguments) {
    if ((targetFunction.requiredParameterCount > arguments.positional.length) ||
        (targetFunction.positionalParameters.length <
            arguments.positional.length)) {
      // Given too few or too many positional arguments
      return false;
    }

    // Do we give named that we don't take?
    Set<String> givenNamed = arguments.named.map((v) => v.name).toSet();
    Set<String> takenNamed =
        targetFunction.namedParameters.map((v) => v.name).toSet();
    givenNamed.removeAll(takenNamed);
    return givenNamed.isEmpty;
  }
}

class SuperInitializerResolutionTransformer extends InitializerVisitor {
  final Class lookupClass;

  SuperInitializerResolutionTransformer(this.lookupClass);

  transformInitializers(List<Initializer> initializers) {
    for (var initializer in initializers) {
      initializer.accept(this);
    }
  }

  visitSuperInitializer(SuperInitializer node) {
    Constructor constructor = node.target;
    if (constructor.enclosingClass != lookupClass) {
      // If [node] refers to a constructor target which is not directly the
      // superclass but some indirect base class then this is because classes in
      // the middle are mixin applications.  These mixin applications will have
      // received a forwarding constructor which we are required to use instead.
      for (var replacement in lookupClass.constructors) {
        if (constructor.name == replacement.name) {
          node.target = replacement;
          return null;
        }
      }

      throw new Exception(
          'Could not find a generative constructor named "${constructor.name}" '
          'in lookup class "${lookupClass.name}"!');
    }
  }
}
