// RUN: %target-typecheck-verify-swift

struct MyType<TyA, TyB> {
  var a : TyA, b : TyB
}

//
// Type aliases that reference unbound generic types -- not really generic,
// but they behave as such, in the sense that you can apply generic
// arguments to them.
//

typealias OurType = MyType

typealias YourType = Swift.Optional

struct Container {
  typealias YourType = Swift.Optional
}

let _: OurType<Int, String>
let _: YourType<Int>
let _: Container.YourType<Int>

//
// Bona-fide generic type aliases
//

typealias DS<T> = MyType<String, T>

typealias BadA<T : Int> = MyType<String, T>  // expected-error {{inheritance from non-protocol, non-class type 'Int'}}

typealias BadB<T where T == Int> = MyType<String, T>  // expected-error {{associated types may not have a generic parameter list}}
// expected-error@-1 {{same-type requirement makes generic parameter 'T' non-generic}}

typealias BadC<T,T> = MyType<String, T>  // expected-error {{definition conflicts with previous value}}
// expected-note @-1 {{previous definition of 'T' is here}}

typealias Tuple2<T1, T2> = (T1, T2)

typealias Tuple3<T1> = (T1, T1) where T1 : Hashable


let _ : Tuple2<Int, String> = (1, "foo")
let _ : Tuple2 = (1, "foo")
let _ : Tuple2<Int, String> = ("bar",  // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
                               "foo")

func f() {
  typealias Tuple2b<T1, T2> = (T1, T2)
  let _ : Tuple2b = (1, "foo")
  
}


typealias A<T1, T2> = MyType<T2, T1>  // expected-note {{generic type 'A' declared here}}

typealias B<T1> = MyType<T1, T1>  // expected-note {{'T1' declared as parameter to type 'B'}}

typealias C<T> = MyType<String, T>

// Type aliases with unused generic params.
typealias D<T1, T2, T3> = MyType<T2, T1>  // expected-note {{'T3' declared as parameter to type 'D'}}

typealias E<T1, T2> = Int  // expected-note {{generic type 'E' declared here}}

typealias F<T1, T2> = (T1) -> T2

// Type alias of type alias.
typealias G<S1, S2> = A<S1, S2>

let _ : E<Int, Float> = 42
let _ : E<Float> = 42   // expected-error {{generic type 'E' specialized with too few type parameters (got 1, but expected 2)}}
let _ : E = 42   // expected-error {{cannot convert value of type 'Int' to specified type 'E'}}
let _ : D = D(a: 1, b: 2)  // expected-error {{cannot convert value of type 'MyType<Int, Int>' to specified type 'D'}}

let _ : D<Int, Int, Float> = D<Int, Int, Float>(a: 1, b: 2)

// FIXME: This is not a great error.
// expected-error @+1 {{cannot convert value of type 'MyType<Int, Int>' to specified type 'D'}}
let _ : D = D<Int, Int, Float>(a: 1, b: 2)


// expected-error @+2 {{generic parameter 'T3' could not be inferred}}
// expected-note @+1 {{explicitly specify the generic arguments to fix this issue}} {{31-31=<Any, Any, Any>}}
let _ : D<Int, Int, Float> = D(a: 1, b: 2)

let _ : F = { (a : Int) -> Int in a }  // Infer the types of F

// TODO QoI: Cannot infer T1/T2.
let _ : F = { a in a }  // expected-error {{type of expression is ambiguous without more context}}

_ = MyType(a: "foo", b: 42)
_ = A(a: "foo", b: 42)
_ = A<Int, String>(a: "foo", b: 42)
_ = A<String, Int>(a: "foo", // expected-error {{'String' is not convertible to 'Int'}}
  b: 42)
_ = B(a: 12, b: 42)
_ = B(a: 12, b: 42 as Float)
_ = B(a: "foo", b: 42)     // expected-error {{generic parameter 'T1' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{6-6=<Any>}}
_ = C(a: "foo", b: 42)
_ = C(a: 42,        // expected-error {{'Int' is not convertible to 'String'}}
  b: 42)

_ = G(a: "foo", b: 42)
_ = G<Int, String>(a: "foo", b: 42)


struct MyTypeWithHashable<TyA, TyB : Hashable> {
}

typealias MTWHInt<HT : Hashable> = MyTypeWithHashable<Int, HT>
typealias MTWHInt2<HT> = MyTypeWithHashable<Int, HT> // expected-error {{type 'HT' does not conform to protocol 'Hashable'}}

func f(a : MyTypeWithHashable<Int, Int>) {
  f(a: MyTypeWithHashable<Int, Int>())
  f(a: MTWHInt<Int>())
}


// Unqualified lookup of generic typealiases nested inside generic contexts
class GenericClass<T> {
  typealias TA<U> = MyType<T, U>
  typealias TAI<U> = MyType<Int, U>

  func testCapture<S>(s: S, t: T) -> TA<S> {
    return TA<S>(a: t, b: s)
  }

  func testCaptureUnbound<S>(s: S, t: T) -> TA<S> {
    return TA(a: t, b: s)
  }

  func testConcrete1(s: Int, t: T) -> TA<Int> {
    return TA<Int>(a: t, b: s)
  }

  func testConcreteUnbound1(s: Int, t: T) -> TA<Int> {
    return TA(a: t, b: s)
  }

  func testConcrete2(s: Float, t: Int) -> TAI<Float> {
    return TAI<Float>(a: t, b: s)
  }

  func testConcreteUnbound2(s: Float, t: Int) -> TAI<Float> {
    return TAI(a: t, b: s)
  }

  // FIXME: Would be nice to preserve sugar here

  func testCaptureInvalid1<S>(s: S, t: T) -> TA<Int> {
    return TA<S>(a: t, b: s) // expected-error {{cannot convert return expression of type 'MyType<T, S>' to return type 'MyType<T, Int>'}}
  }

  func testCaptureInvalid2<S>(s: Int, t: T) -> TA<S> {
    return TA(a: t, b: s) // expected-error {{cannot convert return expression of type 'MyType<T, Int>' to return type 'MyType<T, S>'}}
  }

  struct NestedStruct<U> {
    typealias TA<V> = MyType<(T, V), (U, V)>

    func testCapture<S>(x: (T, S), y: (U, S)) -> TA<S> {
      return TA(a: x, b: y)
    }
  }

  // Stupid corner case -- underlying type is not dependent
  typealias NotDependent<T> = Int

  func misleadingCode(_: NotDependent<String>) {}
}

let gc = GenericClass<Double>()
let fn: MyType<Double, Int> = gc.testCapture(s: 1, t: 1.0)

func use<T>(_ t: T) {}
use(fn)

// Make sure we apply base substitutions to the interface type of the typealias
class ConcreteClass : GenericClass<String> {
  func testSubstitutedCapture1<S>(s: S, t: String) -> TA<S> {
    return TA<S>(a: t, b: s)
  }

  func testSubstitutedCapture2<S>(s: S, t: String) -> TA<S> {
    return TA(a: t, b: s)
  }

  func testSubstitutedCapture3(s: Int, t: String) -> TA<Int> {
    return TA<Int>(a: t, b: s)
  }

  func testSubstitutedCapture4(s: Int, t: String) -> TA<Int> {
    return TA(a: t, b: s)
  }

  func testSubstitutedCapture5(s: Float, t: Int) -> TAI<Float> {
    return TAI<Float>(a: t, b: s)
  }

  func testSubstitutedCapture6(s: Float, t: Int) -> TAI<Float> {
    return TAI(a: t, b: s)
  }
}

// Qualified lookup of generic typealiases nested inside concrete contexts
struct ConcreteStruct {
  typealias O<T> = Optional<T>
}

func takesUnsugaredType1(m: MyType<String, Float>) {}
func takesSugaredType1(m: ConcreteClass.TA<Float>) {
  takesUnsugaredType1(m: m)
}

let _ = ConcreteStruct.O(123)
let _ = ConcreteStruct.O<Int>(123)

let _: ConcreteStruct.O = ConcreteStruct.O(123)
let _: ConcreteStruct.O = ConcreteStruct.O<Int>(123)

let _: ConcreteStruct.O<Int> = ConcreteStruct.O(123)
let _: ConcreteStruct.O<Int> = ConcreteStruct.O<Int>(123)

// Qualified lookup of generic typealiases nested inside generic contexts
//
// FIXME marks cases which still don't work correctly, and either produce a
// spurious diagnostic, or are actually invalid and do not diagnose.
//
// This occurs because the constraint solver does the wrong thing with an
// UnresolvedSpecializeExpr applied to a generic typealias.
//
// In the other cases, we manage to fold the UnresolvedSpecializeExpr in the
// precheckExpression() phase, which handles generic typealiases correctly.

let _ = GenericClass.TA<Float>(a: 4.0, b: 1) // FIXME
let _ = GenericClass.TA<Float>(a: 1, b: 4.0)

let _ = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _ = GenericClass<Int>.TA(a: 1, b: 4.0)

let _ = GenericClass<Int>.TA<Float>(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _ = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)

let _: GenericClass.TA = GenericClass.TA(a: 4.0, b: 1)
let _: GenericClass.TA = GenericClass.TA(a: 1, b: 4.0)

let _: GenericClass.TA = GenericClass.TA<Float>(a: 4.0, b: 1) // FIXME
let _: GenericClass.TA = GenericClass.TA<Float>(a: 1, b: 4.0)

let _: GenericClass.TA = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass.TA = GenericClass<Int>.TA(a: 1, b: 4.0)

let _: GenericClass.TA = GenericClass<Int>.TA<Float>(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass.TA = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)

let _: GenericClass<Int>.TA = GenericClass.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'MyType<Double, Int>' to specified type 'GenericClass<Int>.TA'}}
let _: GenericClass<Int>.TA = GenericClass.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'MyType<Float, Int>' to specified type 'GenericClass<Int>.TA'}}
let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 1, b: 4.0) // FIXME // expected-error {{cannot convert value of type 'MyType<Float, Double>' to specified type 'GenericClass<Int>.TA'}}

let _: GenericClass<Int>.TA = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass<Int>.TA = GenericClass<Int>.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA = GenericClass<Int>.TA<Float>(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass<Int>.TA = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)

let _: GenericClass<Int>.TA<Float> = GenericClass.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'MyType<Double, Int>' to specified type 'MyType<Int, Float>'}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'MyType<Float, Int>' to specified type 'MyType<Int, Float>'}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 1, b: 4.0) // FIXME // expected-error {{cannot convert value of type 'MyType<Float, Double>' to specified type 'MyType<Int, Float>'}}

let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA<Float>(a: 4.0, b: 1) // expected-error {{'Double' is not convertible to 'Int'}}
let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)

func takesUnsugaredType2(m: MyType<Int, Float>) {}
func takesSugaredType2(m: GenericClass<Int>.TA<Float>) {
  takesUnsugaredType2(m: m)
}


//
// Error paths
//

// This works, but in the body of the extension we see the original type
// parameters of A<>'s underlying type MyType<>, rather than the type
// parameters of A<>.
extension A {}

extension A<T> {}  // expected-error {{generic type 'A' specialized with too few type parameters (got 1, but expected 2)}}
extension A<Float,Int> {}  // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}}
extension C<T> {}  // expected-error {{use of undeclared type 'T'}}
extension C<Int> {}  // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}}


protocol ErrorQ {
  associatedtype Y
}
protocol ErrorP {
  associatedtype X: ErrorQ // expected-note {{protocol requires nested type 'X'; do you want to add it?}}
}

typealias ErrorA<T: ErrorP> = T.X.Y

struct ErrorB : ErrorP { // expected-error {{type 'ErrorB' does not conform to protocol 'ErrorP'}}
  typealias X = ErrorC // expected-note {{possibly intended match 'ErrorB.X' (aka 'ErrorC') does not conform to 'ErrorQ'}}
}

struct ErrorC {
  typealias Y = Int
}

typealias Y = ErrorA<ErrorB>

typealias Id<T> = T

extension Id {} // expected-error {{non-nominal type 'Id' cannot be extended}}

class OuterGeneric<T> {
  typealias Alias<T> = AnotherGeneric<T>
  // expected-note@-1 {{generic type 'Alias' declared here}}
  class InnerNonGeneric : Alias {}
  // expected-error@-1 {{reference to generic type 'OuterGeneric<T>.Alias' requires arguments in <...>}}
}

class AnotherGeneric<T> {}

//
// Generic typealiases in protocols
//

protocol P {
  associatedtype A
  typealias G1<T> = MyType<Self, T> // expected-note {{did you mean 'G1'?}}
  typealias G2<T> = MyType<T, A> // expected-note {{did you mean 'G2'?}}
  typealias G3<T> = () -> () // expected-note {{did you mean 'G3'?}}
  typealias G4<T> = (T) -> () // expected-note {{did you mean 'G4'?}}

  func firstRequirement(_: G1<Int>)
  func secondRequirement(_: G2<Int>)
  func thirdRequirement(_: G3<Int>)
  func fourthRequirement(_: G4<Int>)

  func firstRequirementGeneric<T>(_: G1<T>)
  func secondRequirementGeneric<T>(_: G2<T>)
  func thirdRequirementGeneric<T>(_: G3<T>, _: T)
  func fourthRequirementGeneric<T>(_: G4<T>)
}

struct S : P {
  typealias A = Float

  func shouldFail(fn: (Int) -> ()) {
    thirdRequirement(fn)
    // expected-error@-1 {{cannot convert value of type '(Int) -> ()' to expected argument type '() -> ()'}}
  }

  func firstRequirement(_: G1<Int>) {}
  func secondRequirement(_: G2<Int>) {}
  func thirdRequirement(_: G3<Int>) {}
  func fourthRequirement(_: G4<Int>) {}

  func firstRequirementGeneric<T>(_: G1<T>) {
    _ = G1<T>.self // FIXME // expected-error {{use of unresolved identifier 'G1'}}
  }

  func secondRequirementGeneric<T>(_: G2<T>) {
    _ = G2<T>.self // FIXME // expected-error {{use of unresolved identifier 'G2'}}
  }

  func thirdRequirementGeneric<T>(_: G3<T>, _: T) {
    _ = G3<T>.self // FIXME // expected-error {{use of unresolved identifier 'G3'}}
  }

  func fourthRequirementGeneric<T>(_: G4<T>) {
    _ = G4<T>.self // FIXME // expected-error {{use of unresolved identifier 'G4'}}
  }

  func expressionContext() {
    let _: G1 = MyType<S, Int>(a: S(), b: 3)
    let _: G1<Int> = MyType<S, Int>(a: S(), b: 3)

    let _: S.G1 = MyType<S, Int>(a: S(), b: 3)
    let _: S.G1<Int> = MyType<S, Int>(a: S(), b: 3)

    let _: G2 = MyType<Int, Float>(a: 3, b: 1.0)
    let _: G2<Int> = MyType<Int, Float>(a: 3, b: 1.0)

    let _: S.G2 = MyType<Int, Float>(a: 3, b: 1.0)
    let _: S.G2<Int> = MyType<Int, Float>(a: 3, b: 1.0)
  }
}

func takesMyType(x: MyType<S, Int>) {}

func takesMyType(y: MyType<Int, Float>) {}

func f(x: S.G1<Int>, y: S.G2<Int>) {
  takesMyType(x: x)
  takesMyType(y: y)
}

//
// Generic typealiases with requirements
//

typealias Element<S> = S.Iterator.Element where S : Sequence

func takesInt(_: Element<[Int]>) {}

takesInt(10)

func failsRequirementCheck(_: Element<Int>) {}
// expected-error@-1 {{type 'Int' does not conform to protocol 'Sequence'}}
