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

// VMOptions=--lazy-dispatchers
// VMOptions=--no-lazy-dispatchers

import 'dart:math';
import 'package:expect/expect.dart';

Type getType<T>() => T;

void testInstantiateToBounds() {
  f<T extends num, U extends T>() => [T, U];
  g<T extends List<U>, U extends int>() => [T, U];
  h<T extends U, U extends num>(T x, U y) => [T, U];

  // Check that instantiate to bounds creates the correct type arguments
  // during dynamic calls.
  Expect.listEquals([num, num], (f as dynamic)());
  Expect.listEquals([getType<List<int>>(), int], (g as dynamic)());
  Expect.listEquals([num, num], (h as dynamic)(null, null));

  // Check that when instantiate to bounds creates a super-bounded type argument
  // during a dynamic call, an error is thrown.
  i<T extends Iterable<T>>() => null;
  j<T extends Iterable<S>, S extends T>() => null;
  Expect.throwsTypeError(() => (i as dynamic)(), "Super bounded type argument");
  Expect.throwsTypeError(() => (j as dynamic)(), "Super bounded type argument");
}

void testChecksBound() {
  f<T extends num>(T x) => x;
  g<T extends U, U extends num>(T x, U y) => x;

  // Check that arguments are checked against the correct types when instantiate
  // to bounds produces a type argument during a dynamic call.
  Expect.equals((f as dynamic)(42), 42);
  Expect.equals((g as dynamic)(42.0, 100), 42.0);
  Expect.throwsTypeError(() => (f as dynamic)('42'), "Argument check");
  Expect.throwsTypeError(() => (g as dynamic)('hi', 100), "Argument check");

  // Check that an actual type argument is checked against the bound during a
  // dynamic call.
  Expect.equals((f as dynamic)<int>(42), 42);
  Expect.equals((g as dynamic)<double, num>(42.0, 100), 42.0);
  Expect.throwsTypeError(() => (g as dynamic)<double, int>(42.0, 100),
      "Type argument bounds check");
  Expect.throwsTypeError(
      () => (f as dynamic)<Object>(42), "Type argument bounds check");
  Expect.throwsTypeError(() => (g as dynamic)<double, int>(42.0, 100),
      "Type argument bounds check");
  Expect.throwsTypeError(() => (g as dynamic)<num, Object>(42.0, 100),
      "Type argument bounds check");
}

typedef G<U> = num Function<T extends U>(T x);

typedef F<U> = Object Function<T extends U>(T x);

void testSubtype() {
  num f<T extends num>(T x) => x + 2;
  dynamic d = f;

  // Check that casting to an equal generic function type works
  Expect.equals((f as G<num>)(40), 42);
  Expect.equals((d as G<num>)(40), 42);

  // Check that casting to a more general generic function type works
  Expect.equals((f as F<num>)(40), 42);
  Expect.equals((d as F<num>)(40), 42);

  // Check that casting to a generic function with more specific bounds fails
  Expect.throwsTypeError(
      () => (f as G<int>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (d as G<int>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (f as G<double>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (d as G<double>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (f as G<Null>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (d as G<Null>), "Generic functions are invariant");

  // Check that casting to a generic function with a more general bound fails
  Expect.throwsTypeError(
      () => (f as G<Object>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (d as G<Object>), "Generic functions are invariant");

  // Check that casting to a generic function with an unrelated bound fails
  Expect.throwsTypeError(
      () => (f as G<String>), "Generic functions are invariant");
  Expect.throwsTypeError(
      () => (d as G<String>), "Generic functions are invariant");
}

void testToString() {
  num f<T extends num, U extends T>(T x, U y) => min(x, y);
  num g<T, U>(T x, U y) => max(x as num, y as num);
  String h<T, U>(T x, U y) => h.runtimeType.toString();

  // Check that generic method types are printed in a reasonable way
  Expect.isTrue(
      new RegExp(r'<(\w+) extends num, (\w+) extends \1>\(\1, \2\) => num')
          .hasMatch(f.runtimeType.toString()));
  Expect.isTrue(new RegExp(r'<(\w+), (\w+)>\(\1, \2\) => num')
      .hasMatch(g.runtimeType.toString()));
  Expect.isTrue(
      new RegExp(r'<(\w+), (\w+)>\(\1, \2\) => String').hasMatch(h(42, 123.0)));
}

main() {
  testInstantiateToBounds(); //# 01: ok
  testToString(); //# 02: ok
  testChecksBound(); //# 03: ok
  testSubtype(); //# 04: ok
}
