// Copyright (c) 2019, 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" hide Visitor;

import 'package:kernel/core_types.dart' show CoreTypes;

import 'package:kernel/src/bounds_checks.dart' show calculateBounds;

import 'package:kernel/testing/mock_sdk.dart' show mockSdk;

import 'package:kernel/testing/type_parser.dart' as type_parser show parse;

import 'package:kernel/testing/type_parser.dart';

Component parseComponent(String source, Uri uri) {
  Uri coreUri = Uri.parse("dart:core");
  TypeParserEnvironment coreEnvironment =
      new TypeParserEnvironment(coreUri, coreUri);
  Library coreLibrary =
      parseLibrary(coreUri, mockSdk, environment: coreEnvironment);
  TypeParserEnvironment libraryEnvironment = new TypeParserEnvironment(uri, uri)
      ._extend(coreEnvironment._declarations);
  Library library = parseLibrary(uri, source, environment: libraryEnvironment);
  library.name = "lib";
  return new Component(libraries: <Library>[coreLibrary, library]);
}

Library parseLibrary(Uri uri, String text,
    {Uri? fileUri, TypeParserEnvironment? environment}) {
  fileUri ??= uri;
  environment ??= new TypeParserEnvironment(uri, fileUri);
  Library library =
      new Library(uri, fileUri: fileUri, name: uri.path.replaceAll("/", "."));
  List<ParsedType> types = type_parser.parse(text);
  for (ParsedType type in types) {
    if (type is ParsedClass) {
      String name = type.name;
      environment._registerDeclaration(
          name,
          new Class(fileUri: fileUri, name: name)
            ..typeParameters.addAll(new List<TypeParameter>.generate(
                type.typeVariables.length,
                (int i) => new TypeParameter('T$i'))));
    } else if (type is ParsedExtension) {
      String name = type.name;
      environment._registerDeclaration(
          name,
          new Extension(fileUri: fileUri, name: name)
            ..typeParameters.addAll(new List<TypeParameter>.generate(
                type.typeVariables.length,
                (int i) => new TypeParameter('T$i'))));
    }
  }
  for (ParsedType type in types) {
    Node node = environment._kernelFromParsedType(type);
    if (node is Class) {
      library.addClass(node);
    } else if (node is Typedef) {
      library.addTypedef(node);
    } else if (node is Extension) {
      library.addExtension(node);
    } else {
      throw "Unsupported: $node";
    }
  }
  return library;
}

class Env {
  late Component component;

  late CoreTypes coreTypes;

  late TypeParserEnvironment _libraryEnvironment;

  final bool isNonNullableByDefault;

  Env(String source, {required this.isNonNullableByDefault}) {
    // ignore: unnecessary_null_comparison
    assert(isNonNullableByDefault != null);
    Uri libraryUri = Uri.parse('memory:main.dart');
    Uri coreUri = Uri.parse("dart:core");
    TypeParserEnvironment coreEnvironment =
        new TypeParserEnvironment(coreUri, coreUri);
    Library coreLibrary =
        parseLibrary(coreUri, mockSdk, environment: coreEnvironment)
          ..isNonNullableByDefault = isNonNullableByDefault;
    _libraryEnvironment = new TypeParserEnvironment(libraryUri, libraryUri)
        ._extend(coreEnvironment._declarations);
    Library library =
        parseLibrary(libraryUri, source, environment: _libraryEnvironment)
          ..isNonNullableByDefault = isNonNullableByDefault;
    library.name = "lib";
    component = new Component(libraries: <Library>[coreLibrary, library]);
    coreTypes = new CoreTypes(component);
  }

  DartType parseType(String text,
      {Map<String, DartType Function()>? additionalTypes}) {
    return _libraryEnvironment.parseType(text,
        additionalTypes: additionalTypes);
  }

  List<DartType> parseTypes(String text,
      {Map<String, DartType Function()>? additionalTypes}) {
    return _libraryEnvironment.parseTypes(text,
        additionalTypes: additionalTypes);
  }

  List<TypeParameter> extendWithTypeParameters(String? typeParameters) {
    if (typeParameters == null || typeParameters.isEmpty) {
      return <TypeParameter>[];
    }
    ParameterEnvironment parameterEnvironment =
        _libraryEnvironment.extendToParameterEnvironment(typeParameters);
    _libraryEnvironment = parameterEnvironment.environment;
    return parameterEnvironment.parameters;
  }

  void withTypeParameters(
      String? typeParameters, void Function(List<TypeParameter>) f) {
    if (typeParameters == null || typeParameters.isEmpty) {
      f(<TypeParameter>[]);
    } else {
      TypeParserEnvironment oldLibraryEnvironment = _libraryEnvironment;
      List<TypeParameter> typeParameterNodes =
          extendWithTypeParameters(typeParameters);
      f(typeParameterNodes);
      _libraryEnvironment = oldLibraryEnvironment;
    }
  }
}

class TypeParserEnvironment {
  final Uri uri;

  final Uri fileUri;

  final Map<String, TreeNode> _declarations = <String, TreeNode>{};

  final TypeParserEnvironment? _parent;

  /// Collects types to set their nullabilities after type parameters are ready.
  ///
  /// [TypeParameterType]s may receive their nullability at the declaration or
  /// from the bound of the [TypeParameter]s they refer to.  If a
  /// [TypeParameterType] is allocated at the time when the bound of the
  /// [TypeParameter] is not set yet, that is, if it's encountered in that
  /// bound or the bound of other [TypeParameter] from the same scope, and the
  /// nullability of that [TypeParameterType] is not set at declaration, the
  /// [TypeParameterType] is added to [pendingNullabilities], so that it can be
  /// updated when the bound of the [TypeParameter] is ready.
  final List<TypeParameterType> pendingNullabilities = <TypeParameterType>[];

  TypeParserEnvironment(this.uri, this.fileUri, [this._parent]);

  Node _kernelFromParsedType(ParsedType type,
      {Map<String, DartType Function()>? additionalTypes}) {
    Node node = type.accept(
        new _KernelFromParsedType(additionalTypes: additionalTypes), this);
    return node;
  }

  /// Parses a single type.
  DartType parseType(String text,
      {Map<String, DartType Function()>? additionalTypes}) {
    return _kernelFromParsedType(type_parser.parse(text).single,
        additionalTypes: additionalTypes) as DartType;
  }

  /// Parses a list of types separated by commas.
  List<DartType> parseTypes(String text,
      {Map<String, DartType Function()>? additionalTypes}) {
    return (parseType("(${text}) -> void", additionalTypes: additionalTypes)
            as FunctionType)
        .positionalParameters;
  }

  bool isObject(String name) => name == "Object" && "$uri" == "dart:core";

  Class get objectClass => lookupDeclaration("Object") as Class;

  TreeNode lookupDeclaration(String name) {
    TreeNode? result = _declarations[name];
    if (result == null && _parent != null) {
      return _parent!.lookupDeclaration(name);
    }
    if (result == null) throw "Not found: $name";
    return result;
  }

  T _registerDeclaration<T extends TreeNode>(String name, T declaration) {
    TreeNode? existing = _declarations[name];
    if (existing != null) {
      throw "Duplicated declaration: $name";
    }
    return _declarations[name] = declaration;
  }

  TypeParserEnvironment _extend(Map<String, TreeNode> declarations) {
    return new TypeParserEnvironment(uri, fileUri, this)
      .._declarations.addAll(declarations);
  }

  TypeParserEnvironment extendWithTypeParameters(String? typeParameters) {
    if (typeParameters?.isEmpty ?? true) return this;
    return extendToParameterEnvironment(typeParameters!).environment;
  }

  ParameterEnvironment extendToParameterEnvironment(String typeParameters) {
    // ignore: unnecessary_null_comparison
    assert(typeParameters != null && typeParameters.isNotEmpty);
    return const _KernelFromParsedType().computeTypeParameterEnvironment(
        parseTypeVariables("<${typeParameters}>"), this);
  }

  /// Returns the predefined type by the [name], if any.
  ///
  /// Use this in subclasses to add support for additional predefined types.
  DartType? getPredefinedNamedType(String name) {
    if (_parent != null) {
      return _parent!.getPredefinedNamedType(name);
    }
    return null;
  }
}

class _KernelFromParsedType implements Visitor<Node, TypeParserEnvironment> {
  final Map<String, DartType Function()>? additionalTypes; // Can be null.

  const _KernelFromParsedType({this.additionalTypes});

  DartType _parseType(ParsedType type, TypeParserEnvironment environment) {
    return type.accept<Node, TypeParserEnvironment>(this, environment)
        as DartType;
  }

  InterfaceType? _parseOptionalInterfaceType(
      ParsedType? type, TypeParserEnvironment environment) {
    return type?.accept<Node, TypeParserEnvironment>(this, environment)
        as InterfaceType?;
  }

  @override
  DartType visitInterfaceType(
      ParsedInterfaceType node, TypeParserEnvironment environment) {
    String name = node.name;
    DartType? predefined = environment.getPredefinedNamedType(name);
    if (predefined != null) {
      return predefined;
    } else if (name == "dynamic") {
      // Don't return a const object to ensure we test implementations that use
      // identical.
      return new DynamicType();
    } else if (name == "void") {
      // Don't return a const object to ensure we test implementations that use
      // identical.
      return new VoidType();
    } else if (name == "Never") {
      // Don't return a const object to ensure we test implementations that use
      // identical.
      return NeverType.fromNullability(
          interpretParsedNullability(node.parsedNullability));
    } else if (name == "Null") {
      // Don't return a const object to ensure we test implementations that use
      // identical.
      return new NullType();
    } else if (name == "invalid") {
      // Don't return a const object to ensure we test implementations that use
      // identical.
      return new InvalidType();
    } else if (additionalTypes != null && additionalTypes!.containsKey(name)) {
      return additionalTypes![name]!.call();
    }
    TreeNode declaration = environment.lookupDeclaration(name);
    List<ParsedType> arguments = node.arguments;
    List<DartType> kernelArguments =
        new List<DartType>.filled(arguments.length, dummyDartType);
    for (int i = 0; i < arguments.length; i++) {
      kernelArguments[i] = _parseType(arguments[i], environment);
    }
    if (name == "FutureOr") {
      return new FutureOrType(kernelArguments.single,
          interpretParsedNullability(node.parsedNullability));
    }
    if (declaration is Class) {
      Nullability nullability =
          interpretParsedNullability(node.parsedNullability);
      if (declaration.name == 'Null' &&
          declaration.enclosingLibrary.importUri.isScheme('dart') &&
          declaration.enclosingLibrary.importUri.path == 'core') {
        if (node.parsedNullability != ParsedNullability.omitted) {
          throw "Null type must be written without explicit nullability";
        }
        nullability = Nullability.nullable;
      }
      List<TypeParameter> typeVariables = declaration.typeParameters;
      if (kernelArguments.isEmpty && typeVariables.isNotEmpty) {
        kernelArguments =
            new List<DartType>.filled(typeVariables.length, dummyDartType);
        for (int i = 0; i < typeVariables.length; i++) {
          kernelArguments[i] = typeVariables[i].defaultType;
        }
      } else if (kernelArguments.length != typeVariables.length) {
        throw "Expected ${typeVariables.length} type arguments: $node";
      }
      return new InterfaceType(declaration, nullability, kernelArguments);
    } else if (declaration is TypeParameter) {
      if (arguments.isNotEmpty) {
        throw "Type variable can't have arguments (${node.name})";
      }
      Nullability nullability =
          identical(declaration.bound, TypeParameter.unsetBoundSentinel)
              ? Nullability.nonNullable
              : TypeParameterType.computeNullabilityFromBound(declaration);
      TypeParameterType type = new TypeParameterType(
          declaration,
          interpretParsedNullability(node.parsedNullability,
              ifOmitted: nullability));
      // If the nullability was omitted on the type and can't be computed from
      // the bound because it's not yet available, it will be set to null.  In
      // that case, put it to the list to be updated later, when the bound is
      // available.
      // ignore: unnecessary_null_comparison
      if (type.declaredNullability == null) {
        environment.pendingNullabilities.add(type);
      }
      return type;
    } else if (declaration is Typedef) {
      return new TypedefType(declaration,
          interpretParsedNullability(node.parsedNullability), kernelArguments);
    } else if (declaration is Extension) {
      return new ExtensionType(declaration,
          interpretParsedNullability(node.parsedNullability), kernelArguments);
    } else {
      throw "Unhandled ${declaration.runtimeType}";
    }
  }

  @override
  Class visitClass(ParsedClass node, TypeParserEnvironment environment) {
    String name = node.name;
    Class cls = environment.lookupDeclaration(name) as Class;
    ParameterEnvironment parameterEnvironment =
        computeTypeParameterEnvironment(node.typeVariables, environment);
    List<TypeParameter> parameters = parameterEnvironment.parameters;
    setParents(parameters, cls);
    cls.typeParameters
      ..clear()
      ..addAll(parameters);
    {
      TypeParserEnvironment environment = parameterEnvironment.environment;
      InterfaceType? type =
          _parseOptionalInterfaceType(node.supertype, environment);
      if (type == null) {
        if (!environment.isObject(name)) {
          cls.supertype = environment.objectClass.asRawSupertype;
        }
      } else {
        cls.supertype = toSupertype(type);
      }
      InterfaceType? mixedInType =
          _parseOptionalInterfaceType(node.mixedInType, environment);
      if (mixedInType != null) {
        cls.mixedInType = toSupertype(mixedInType);
      }
      List<ParsedType> interfaces = node.interfaces;
      for (int i = 0; i < interfaces.length; i++) {
        cls.implementedTypes.add(toSupertype(
            _parseOptionalInterfaceType(interfaces[i], environment)!));
      }
    }
    return cls;
  }

  @override
  Extension visitExtension(
      ParsedExtension node, TypeParserEnvironment environment) {
    String name = node.name;
    Extension ext = environment.lookupDeclaration(name) as Extension;
    ParameterEnvironment parameterEnvironment =
        computeTypeParameterEnvironment(node.typeVariables, environment);
    List<TypeParameter> parameters = parameterEnvironment.parameters;
    setParents(parameters, ext);
    ext.typeParameters
      ..clear()
      ..addAll(parameters);
    {
      TypeParserEnvironment environment = parameterEnvironment.environment;
      DartType onType = node.onType
          .accept<Node, TypeParserEnvironment>(this, environment) as DartType;
      ext.onType = onType;
    }
    return ext;
  }

  @override
  Typedef visitTypedef(ParsedTypedef node, TypeParserEnvironment environment) {
    String name = node.name;
    Typedef def = environment._registerDeclaration(
        name, new Typedef(name, null, fileUri: environment.fileUri));
    ParameterEnvironment parameterEnvironment =
        computeTypeParameterEnvironment(node.typeVariables, environment);
    def.typeParameters.addAll(parameterEnvironment.parameters);
    DartType type;
    {
      TypeParserEnvironment environment = parameterEnvironment.environment;
      type = _parseType(node.type, environment);
      if (type is FunctionType) {
        FunctionType f = type;
        type = new FunctionType(
            f.positionalParameters, f.returnType, Nullability.nonNullable,
            namedParameters: f.namedParameters,
            typeParameters: f.typeParameters,
            requiredParameterCount: f.requiredParameterCount);
      }
    }
    return def..type = type;
  }

  @override
  FunctionType visitFunctionType(
      ParsedFunctionType node, TypeParserEnvironment environment) {
    ParameterEnvironment parameterEnvironment =
        computeTypeParameterEnvironment(node.typeVariables, environment);
    List<DartType> positionalParameters = <DartType>[];
    List<NamedType> namedParameters = <NamedType>[];
    DartType returnType;
    {
      TypeParserEnvironment environment = parameterEnvironment.environment;
      returnType = _parseType(node.returnType, environment);
      for (ParsedType argument in node.arguments.required) {
        positionalParameters.add(_parseType(argument, environment));
      }
      for (ParsedType argument in node.arguments.positional) {
        positionalParameters.add(_parseType(argument, environment));
      }
      for (ParsedNamedArgument argument in node.arguments.named) {
        namedParameters.add(new NamedType(
            argument.name, _parseType(argument.type, environment),
            isRequired: argument.isRequired));
      }
    }
    namedParameters.sort();
    return new FunctionType(positionalParameters, returnType,
        interpretParsedNullability(node.parsedNullability),
        namedParameters: namedParameters,
        requiredParameterCount: node.arguments.required.length,
        typeParameters: parameterEnvironment.parameters);
  }

  @override
  VoidType visitVoidType(
      ParsedVoidType node, TypeParserEnvironment environment) {
    return const VoidType();
  }

  @override
  TypeParameter visitTypeVariable(
      ParsedTypeVariable node, TypeParserEnvironment environment) {
    throw "not implemented: $node";
  }

  @override
  TypeParameterType visitIntersectionType(
      ParsedIntersectionType node, TypeParserEnvironment environment) {
    TypeParameterType type =
        _parseType(node.a, environment) as TypeParameterType;
    DartType bound = _parseType(node.b, environment);
    return new TypeParameterType.intersection(
        type.parameter, type.nullability, bound);
  }

  Supertype toSupertype(InterfaceType type) {
    return new Supertype.byReference(type.className, type.typeArguments);
  }

  ParameterEnvironment computeTypeParameterEnvironment(
      List<ParsedTypeVariable> typeVariables,
      TypeParserEnvironment environment) {
    List<TypeParameter> typeParameters = new List<TypeParameter>.filled(
        typeVariables.length, dummyTypeParameter);
    Map<String, TypeParameter> typeParametersByName = <String, TypeParameter>{};
    for (int i = 0; i < typeVariables.length; i++) {
      String name = typeVariables[i].name;
      typeParametersByName[name] = typeParameters[i] = new TypeParameter(name);
    }
    TypeParserEnvironment nestedEnvironment =
        environment._extend(typeParametersByName);
    Class objectClass = environment.objectClass;
    for (int i = 0; i < typeVariables.length; i++) {
      ParsedType? bound = typeVariables[i].bound;
      TypeParameter typeParameter = typeParameters[i];
      if (bound == null) {
        typeParameter
          ..bound = new InterfaceType(
              objectClass, Nullability.nullable, const <DartType>[])
          ..defaultType = const DynamicType();
      } else {
        DartType type = _parseType(bound, nestedEnvironment);
        typeParameter
          ..bound = type
          // The default type will be overridden below, but we need to set it
          // so [calculateBounds] can distinguish between explicit and implicit
          // bounds.
          ..defaultType = type;
      }
    }
    Uri uri = new Uri.file("test.lib");
    List<DartType> defaultTypes = calculateBounds(typeParameters, objectClass,
        new Library(uri, fileUri: uri)..isNonNullableByDefault = true);
    for (int i = 0; i < typeParameters.length; i++) {
      typeParameters[i].defaultType = defaultTypes[i];
    }

    for (TypeParameterType type in nestedEnvironment.pendingNullabilities) {
      type.declaredNullability =
          TypeParameterType.computeNullabilityFromBound(type.parameter);
    }
    nestedEnvironment.pendingNullabilities.clear();
    return new ParameterEnvironment(typeParameters, nestedEnvironment);
  }
}

class ParameterEnvironment {
  final List<TypeParameter> parameters;
  final TypeParserEnvironment environment;

  const ParameterEnvironment(this.parameters, this.environment);
}
