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

import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;

import '../common.dart';
import '../elements/entities.dart';

/// Returns a textual representation of [node] that include the runtime type and
/// hash code of the node and a one line prefix of the node toString text.
String nodeToDebugString(ir.Node node, [int textLength = 40]) {
  String blockText = node.toString().replaceAll('\n', ' ');
  if (blockText.length > textLength) {
    blockText = blockText.substring(0, textLength - 3) + '...';
  }
  return '(${node.runtimeType}:${node.hashCode})${blockText}';
}

/// Comparator for the canonical order or named parameters.
// TODO(johnniwinther): Remove this when named parameters are sorted in dill.
int namedOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) {
  return a.name.compareTo(b.name);
}

/// Comparator for the declaration order of parameters.
int nativeOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) {
  return a.fileOffset.compareTo(b.fileOffset);
}

SourceSpan computeSourceSpanFromTreeNode(ir.TreeNode node) {
  // TODO(johnniwinther): Use [ir.Location] directly as a [SourceSpan].
  Uri uri;
  int offset;
  while (node != null) {
    if (node.fileOffset != ir.TreeNode.noOffset) {
      offset = node.fileOffset;
      // @patch annotations have no location.
      uri = node.location?.file;
      break;
    }
    node = node.parent;
  }
  if (uri != null) {
    return new SourceSpan(uri, offset, offset + 1);
  }
  return null;
}

/// Returns the `AsyncMarker` corresponding to `node.asyncMarker`.
AsyncMarker getAsyncMarker(ir.FunctionNode node) {
  switch (node.asyncMarker) {
    case ir.AsyncMarker.Async:
      return AsyncMarker.ASYNC;
    case ir.AsyncMarker.AsyncStar:
      return AsyncMarker.ASYNC_STAR;
    case ir.AsyncMarker.Sync:
      return AsyncMarker.SYNC;
    case ir.AsyncMarker.SyncStar:
      return AsyncMarker.SYNC_STAR;
    case ir.AsyncMarker.SyncYielding:
    default:
      throw new UnsupportedError(
          "Async marker ${node.asyncMarker} is not supported.");
  }
}

/// Returns the `Variance` corresponding to `node.variance`.
Variance convertVariance(ir.TypeParameter node) {
  if (node.isLegacyCovariant) return Variance.legacyCovariant;
  switch (node.variance) {
    case ir.Variance.covariant:
      return Variance.covariant;
    case ir.Variance.contravariant:
      return Variance.contravariant;
    case ir.Variance.invariant:
      return Variance.invariant;
    default:
      throw new UnsupportedError("Variance ${node.variance} is not supported.");
  }
}

/// Returns `true` if [node] is a null literal or a null constant.
bool isNullLiteral(ir.Expression node) {
  return node is ir.NullLiteral ||
      (node is ir.ConstantExpression && node.constant is ir.NullConstant);
}

/// Kernel encodes a null-aware expression `a?.b` as
///
///     let final #1 = a in #1 == null ? null : #1.b
///
/// [getNullAwareExpression] recognizes such expressions storing the result in
/// a [NullAwareExpression] object.
///
/// [syntheticVariable] holds the synthesized `#1` variable. [expression] holds
/// the `#1.b` expression. [receiver] returns `a` expression. [parent] returns
/// the parent of the let node, i.e. the parent node of the original null-aware
/// expression. [let] returns the let node created for the encoding.
class NullAwareExpression {
  final ir.VariableDeclaration syntheticVariable;
  final ir.Expression expression;

  NullAwareExpression(this.syntheticVariable, this.expression);

  ir.Expression get receiver => syntheticVariable.initializer;

  ir.TreeNode get parent => syntheticVariable.parent.parent;

  ir.Let get let => syntheticVariable.parent;

  @override
  String toString() => let.toString();
}

NullAwareExpression getNullAwareExpression(ir.TreeNode node) {
  if (node is ir.Let) {
    ir.Expression body = node.body;
    if (node.variable.name == null &&
        node.variable.isFinal &&
        body is ir.ConditionalExpression &&
        body.condition is ir.MethodInvocation &&
        isNullLiteral(body.then)) {
      ir.MethodInvocation invocation = body.condition;
      ir.Expression receiver = invocation.receiver;
      if (invocation.name.text == '==' &&
          receiver is ir.VariableGet &&
          receiver.variable == node.variable &&
          isNullLiteral(invocation.arguments.positional.single)) {
        // We have
        //   let #t1 = e0 in #t1 == null ? null : e1
        return new NullAwareExpression(node.variable, body.otherwise);
      }
    }
  }
  return null;
}

/// Check whether [node] is immediately guarded by a
/// [ir.CheckLibraryIsLoaded], and hence the node is a deferred access.
ir.LibraryDependency getDeferredImport(ir.TreeNode node) {
  // Note: this code relies on the CFE generating the code as we expect it here.
  // If one day we optimize away redundant CheckLibraryIsLoaded instructions,
  // we'd need to derive this information directly from the CFE (See #35005),
  ir.TreeNode parent = node.parent;

  // TODO(sigmund): remove when CFE generates the correct tree (#35320). For
  // instance, it currently generates
  //
  //   let _ = check(prefix) in (prefix::field.property)
  //
  // instead of:
  //
  //   (let _ = check(prefix) in prefix::field).property
  if (node is ir.StaticGet || node is ir.ConstantExpression) {
    while (parent is ir.PropertyGet || parent is ir.MethodInvocation) {
      parent = parent.parent;
    }
  }

  if (parent is ir.Let) {
    var initializer = parent.variable.initializer;
    if (initializer is ir.CheckLibraryIsLoaded) {
      return initializer.import;
    }
  }
  return null;
}

class _FreeVariableVisitor implements ir.DartTypeVisitor<bool> {
  const _FreeVariableVisitor();

  bool visit(ir.DartType type) {
    if (type != null) return type.accept(this);
    return false;
  }

  bool visitList(List<ir.DartType> types) {
    for (ir.DartType type in types) {
      if (visit(type)) return true;
    }
    return false;
  }

  @override
  bool visitTypedefType(ir.TypedefType node) {
    return visitList(node.typeArguments);
  }

  @override
  bool visitTypeParameterType(ir.TypeParameterType node) {
    return true;
  }

  @override
  bool visitFunctionType(ir.FunctionType node) {
    if (visit(node.returnType)) return true;
    if (visitList(node.positionalParameters)) return true;
    for (ir.NamedType namedType in node.namedParameters) {
      if (visit(namedType.type)) return true;
    }
    return false;
  }

  @override
  bool visitInterfaceType(ir.InterfaceType node) {
    return visitList(node.typeArguments);
  }

  @override
  bool visitFutureOrType(ir.FutureOrType node) {
    return visit(node.typeArgument);
  }

  @override
  bool visitBottomType(ir.BottomType node) => false;

  @override
  bool visitNeverType(ir.NeverType node) => false;

  @override
  bool visitVoidType(ir.VoidType node) => false;

  @override
  bool visitDynamicType(ir.DynamicType node) => false;

  @override
  bool visitInvalidType(ir.InvalidType node) => false;

  @override
  bool defaultDartType(ir.DartType node) {
    throw new UnsupportedError("FreeVariableVisitor.defaultTypeNode");
  }
}

/// Returns `true` if [type] contains a type variable.
///
/// All type variables (class type variables, generic method type variables,
/// and function type variables) are considered.
bool containsFreeVariables(ir.DartType type) =>
    type.accept(const _FreeVariableVisitor());
