diff --git a/TypeConstraints.ts b/TypeConstraints.ts new file mode 100644 index 0000000000000..74a9b9277bc48 --- /dev/null +++ b/TypeConstraints.ts @@ -0,0 +1,252 @@ +// TypeScript not expose TypeConstructor +enum TypeFlag { + AppliedType = 1 << 0, + TypeBounds = 1 << 1, + TypeParamRef = 1 << 2, + TypeVar = 1 << 3, +} + +interface Type { +} + +/// A type application `TC[T_1, ..., T_n]` +interface AppliedType extends Type { + typeConstructor: Type, // In fact, typeConstructor must be a type lambda now. + arguments: Type[] +} + +interface TypeMapper { } + +interface TypeBounds extends Type { + upperBound: Type; + // lowerBound: Type + // ATTENTION. In dotty(Scala3 compiler), it define `&` and `|` opeator, which use logic + // &(that: ) => TypeBounds(this.lo | that.lo, this.hi & that.hi) + // | => TypeBounds(this.lo & that.lo, this.hi | that.hi) +} + +interface TypeParamRef extends Type { + binder: TypeLambda; + paramNum: number; +} + +/** In a TypeApply tree, a TypeVar is created for each argument type to be inferred. + * Every type variable is referred to by exactly one inferred type parameter of some + * TypeApply tree. + * + * A type variable is essentially a switch that models some part of a substitution. + * It is first linked to `origin`, a poly param that's in the current constraint set. + * It can then be (once) instantiated to some other type. The instantiation is + * recorded in the type variable itself, or else, if the current type state + * is different from the variable's creation state (meaning unrolls are possible) + * in the current typer state. + * + * @param origin The parameter that's tracked by the type variable. + * @param creatorState The typer state in which the variable was created. + */ +interface TypeVar extends Type { + currentOrigin: TypeParamRef; + isInstantited: Boolean; + /** The permanent instance type of the variable, or NoType is none is given yet */ + myInst: Type;// = NoType; + /** Instantiate variable with given type */ + instantiateWith(type: Type): Type; + // scala + // {assert(tp ne this, s"self instantiation of ${tp.show}, constraint = ${ctx.typerState.constraint.show}") + // typr.println(s"instantiating ${this.show} with ${tp.show}") + // if ((ctx.typerState eq owningState.get) && !TypeComparer.subtypeCheckInProgress) + // inst = tp + // ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, tp) + // tp} +} + + +// type lambda is just type constructor, which takes type as parameter and return type. +interface TypeLambda extends Type { + paramNames: string[]; + paramInfos: TypeBounds[]; + param: { name: string, bounds: TypeBounds }[]; + /** + * must be a proper type. + */ + resType: Type; + /** + * Always get this from getter function `GetTypeParamRefFromTypeLambda` + */ + paramRefs: TypeParamRef[]; +} + +function GetTypeParamRefFromTypeLambda(tl: TypeLambda) { + if (!!tl.paramRefs) { + const tmpParamRefs: TypeParamRef[] = []; + for (const index in tl.paramNames) { + tmpParamRefs[index] = { binder: tl, paramNum: parseInt(index) }; + } + tl.paramRefs = tmpParamRefs; + } + return tl.paramRefs; +} + +// Constraint of "A" ($"{ConstraintA}") <: Constraint of "B" ($"ConstraintB") +// trait TermLambda extends LambdaType {} + +// trait TypeLambda extends LambdaType { +// type ThisName = TypeName +// type PInfo = TypeBounds +// type This <: TypeLambda +// type ParamRefType = TypeParamRef + +// def isResultDependent(using Context): Boolean = true +// def isParamDependent(using Context): Boolean = true + +// def newParamRef(n: Int): TypeParamRef = new TypeParamRefImpl(this, n) + +// @threadUnsafe lazy val typeParams: List[LambdaParam] = +// paramNames.indices.toList.map(new LambdaParam(this, _)) + +// def derivedLambdaAbstraction(paramNames: List[TypeName], paramInfos: List[TypeBounds], resType: Type)(using Context): Type = +// resType match { +// case resType: AliasingBounds => +// resType.derivedAlias(newLikeThis(paramNames, paramInfos, resType.alias)) +// case resType @ TypeBounds(lo, hi) => +// resType.derivedTypeBounds( +// if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramInfos, lo), +// newLikeThis(paramNames, paramInfos, hi)) +// case _ => +// derivedLambdaType(paramNames, paramInfos, resType) +// } +// } + +// trait LambdaType extends BindingType with TermType { self => +// type ThisName <: Name +// type PInfo <: Type +// type This <: LambdaType{type PInfo = self.PInfo} +// type ParamRefType <: ParamRef + +// def paramNames: List[ThisName] +// def paramInfos: List[PInfo] +// def resType: Type +// protected def newParamRef(n: Int): ParamRefType + +// override def resultType(using Context): Type = resType + +// def isResultDependent(using Context): Boolean +// def isParamDependent(using Context): Boolean + +// final def isTermLambda: Boolean = isInstanceOf[TermLambda] +// final def isTypeLambda: Boolean = isInstanceOf[TypeLambda] +// final def isHigherKinded: Boolean = isInstanceOf[TypeProxy] + +// private var myParamRefs: List[ParamRefType] = null + +// def paramRefs: List[ParamRefType] = { +// if myParamRefs == null then +// def recur(paramNames: List[ThisName], i: Int): List[ParamRefType] = +// paramNames match +// case _ :: rest => newParamRef(i) :: recur(rest, i + 1) +// case _ => Nil +// myParamRefs = recur(paramNames, 0) +// myParamRefs +// } + +// /** Like `paramInfos` but substitute parameter references with the given arguments */ +// final def instantiateParamInfos(argTypes: => List[Type])(using Context): List[Type] = +// if (isParamDependent) paramInfos.mapConserve(_.substParams(this, argTypes)) +// else paramInfos + +// /** Like `resultType` but substitute parameter references with the given arguments */ +// final def instantiate(argTypes: => List[Type])(using Context): Type = +// if (isResultDependent) resultType.substParams(this, argTypes) +// else resultType + +// def companion: LambdaTypeCompanion[ThisName, PInfo, This] + +// /** The type `[tparams := paramRefs] tp`, where `tparams` can be +// * either a list of type parameter symbols or a list of lambda parameters +// */ +// def integrate(tparams: List[ParamInfo], tp: Type)(using Context): Type = +// (tparams: @unchecked) match { +// case LambdaParam(lam, _) :: _ => tp.subst(lam, this) +// case params: List[Symbol @unchecked] => tp.subst(params, paramRefs) +// } + +// final def derivedLambdaType(paramNames: List[ThisName] = this.paramNames, +// paramInfos: List[PInfo] = this.paramInfos, +// resType: Type = this.resType)(using Context): LambdaType = +// if ((paramNames eq this.paramNames) && (paramInfos eq this.paramInfos) && (resType eq this.resType)) this +// else newLikeThis(paramNames, paramInfos, resType) + +// def newLikeThis(paramNames: List[ThisName], paramInfos: List[PInfo], resType: Type)(using Context): This = +// def substParams(pinfos: List[PInfo], to: This): List[PInfo] = pinfos match +// case pinfos @ (pinfo :: rest) => +// pinfos.derivedCons(pinfo.subst(this, to).asInstanceOf[PInfo], substParams(rest, to)) +// case nil => +// nil +// companion(paramNames)( +// x => substParams(paramInfos, x), +// x => resType.subst(this, x)) + +// protected def prefixString: String +// override def toString: String = s"$prefixString($paramNames, $paramInfos, $resType)" +// } + + +/** Distributes Lambda inside type bounds. Examples: + * + * type T[X] = U becomes type T = [X] -> U + * type T[X] <: U becomes type T >: Nothing <: ([X] -> U) + * type T[X] >: L <: U becomes type T >: ([X] -> L) <: ([X] -> U) + * + * The variances of regular TypeBounds types, as well as of match aliases + * and of opaque aliases are always determined from the given parameters + * `params`. The variances of other type aliases are determined from + * the given parameters only if one of these parameters carries a `+` + * or `-` variance annotation. Type aliases without variance annotation + * are treated structurally. That is, their parameter variances are + * determined by how the parameter(s) appear in the result type. + * + * Examples: + * + * type T[X] >: A // X is invariant + * type T[X] <: List[X] // X is invariant + * type T[X] = List[X] // X is covariant (determined structurally) + * opaque type T[X] = List[X] // X is invariant + * opaque type T[+X] = List[X] // X is covariant + * type T[A, B] = A => B // A is contravariant, B is covariant (determined structurally) + * type T[A, +B] = A => B // A is invariant, B is covariant + */ + +// type Set[T] +// type Set T => T +// type T[X] >: L <: U +// becomes type T >: ([X] =>> L) <: ([X] =>> U) +// type T[X] <: X => X +// becomes type T >: Nothing <: ([X] =>> X => X) +// [F[X] <: Coll[X]] +// becomes [F >: Nothing <: [X] =>> Coll[X]] + +// def boundsFromParams[PI <: ParamInfo.Of[TypeName]](params: List[PI], bounds: TypeBounds)(using Context): TypeBounds = { +// def expand(tp: Type, useVariances: Boolean) = +// if params.nonEmpty && useVariances then +// apply(params.map(_.paramName), params.map(_.paramVariance))( +// tl => params.map(param => toPInfo(tl.integrate(params, param.paramInfo))), +// tl => tl.integrate(params, tp)) +// else +// super.fromParams(params, tp) +// def isOpaqueAlias = params match +// case (param: Symbol) :: _ => param.owner.is(Opaque) +// case _ => false +// bounds match { +// case bounds: MatchAlias => +// bounds.derivedAlias(expand(bounds.alias, true)) +// case bounds: TypeAlias => +// bounds.derivedAlias(expand(bounds.alias, +// isOpaqueAlias || params.exists(!_.paramVariance.isEmpty))) +// case TypeBounds(lo, hi) => +// bounds.derivedTypeBounds( +// if lo.isRef(defn.NothingClass) then lo else expand(lo, true), +// expand(hi, true)) +// } +// } +// } + diff --git a/src/HKT.md b/src/HKT.md new file mode 100644 index 0000000000000..be9e0d9619371 --- /dev/null +++ b/src/HKT.md @@ -0,0 +1,242 @@ + + +Convert `Type Constructor Instance` to `Type Lambda` +`List = [T] =>> List[T]` + +Convert `apply constraint` to `Type Lambda` +`type T[X] >: L <: U` convert to `type T >: ([X] =>> L) <: ([X] =>> U)` + +Define `<:` on `TypeLambda`: +`type TL1 = [X >: L1 <: U1] =>> R1` +`type TL2 = [X >: L2 <: U2] =>> R2` +`TL1 <: TL2` if + - the type interval `L2..U2` is contained in the type interval `L1..U1` (i.e. `L1 <: L2` and `U2 <: U1`) and + - `R1 <: R2` +The conditions are reasonable: assume we have `interface F[G[T<:U1] <: G1[T]]`, `G[Timpl]`, so `Timpl <: U1`, +then we replace `G[T]` with `Gimpl[U<:U2] <: G2[U]`, if the U is stricter(`U2<:U1`), Timpl might not meet `Timpl <: U2`; +And we use functions in `G1[T]`, if `G2[U] <: G1[T]` these functions might not exist. + +`List[List[T]]` +`Functor[List]` +^ Object ^ TypeLambdaInstance + +If `A <: B` +`A` and `B` both have met the contraints. +TypeLambda[A] = TypeLambda[B] is valid if TypeLambda[+T]; +TypeLambda[B] = TypeLambda[A] is valid if TypeLambda[-T]; + +Whether one proper type `A` is the subtype of another type `B`? + +- A: * +- B: * +- A <: B? + +1. A and B are not applicated by TypeLambda. + Only inheritance. + A <: B iff A inheritances B + +2. A and B are applicated by TypeLambda, like `List` + A is like TypeLambda_A$a0$a1... + B is like TypeLambda_B$b0$b1... + $ai and $bi is the typeArgument + + we could assume there are only two parameters + So, we want: + + TypeLambda_A$a0$a1 <: TypeLambda_B$b0$b1 + + If we have + 1. TypeLambda_A extends TypeLambda_Ii... extends TypeLambda_B + + 2. And we assume we have got a variance array of type argument(this array might be infered, might be annotation from A, might be annotation from B, anyway, we have got one.) + + if variance of i is covariance, we need $ai <: $bi + if variance of i is cotravariance, we need $bi <: $ai + + It is obvious we could get TypeLambda_A$a0$a1 <: TypeLambda_B$b0$b1 if 1 and 2 are both true. + + TypeLambda_A$a0$a1 <: TypeLambda_B$a0$a1 <: TypeLambda_B$b0$b1 + + +Let us define declaration and instance here: +As long as it is not a declaration, it is a instance. +only one type first appear, it is a declaration. +interface II extends Set> + ^ ^ both are instance + ^ This is a proper type Set + +You might thought this is not enough! But in scala, it is OK to see following code: + class Derived1{} + class Derived2 extends Derived1{} + class Derived3 extends Derived2{} + class C1[Generic[X <: Derived2] <: Set[U], U <: Derived1]{} + class C2[Generic[X <: Derived2] <: Set[U], U <: Derived2]{} + class C3[Generic[X <: Derived2] <: Set[U], U <: Derived3]{} + class C4[Generic[X <: Derived1] <: Set[U], U <: Derived2]{} + class C5[Generic[X <: Derived2] <: Set[U], U <: Derived2]{} + class C6[Generic[X <: Derived3] <: Set[U], U <: Derived2]{} + class C7[Generic[X <: Derived2] <: Set[X], U <: Derived2]{} + + var v1 = new C1[Set, Derived1](); + var v2 = new C2[Set, Derived2](); + var v3 = new C3[Set, Derived3](); + var v4 = new C4[Set, Derived2](); + var v5 = new C5[Set, Derived2](); + var v6 = new C6[Set, Derived2](); + var v7 = new C7[List, Derived2](); + +Type argument List does not conform to upper bound [X <: test2.Derived2] =>> Set[X] +Constraint( + uninstVars = ; + constrained types = + bounds = + ordering = +) +Subtype trace: + ==> List <:< [X <: test2.Derived2] =>> Set[X] + ==> List <:< [X <: test2.Derived2] =>> Set[X] recur + ==> List <:< [X <: test2.Derived2] =>> Set[X] recur + ==> <: test2.Derived2 <:< + ==> <: test2.Derived2 <:< recur + <== <: test2.Derived2 <:< recur = true + <== <: test2.Derived2 <:< = true + ==> List[A] <:< Set[A] + ==> List[A] <:< Set[A] recur + <== List[A] <:< Set[A] recur = false + <== List[A] <:< Set[A] = false + <== List <:< [X <: test2.Derived2] =>> Set[X] recur = false + <== List <:< [X <: test2.Derived2] =>> Set[X] recur = false + <== List <:< [X <: test2.Derived2] =>> Set[X] = false + +``` +isProperTypeLessThan(Type type1, Type type2){ + // assume0/TODO: We have checked constraints! + // assume1/TODO: type1 and type2 are proper type! + // assume2/TODO: type are interface/class, if it is Object, it should pass its `target` until it is one of these. + // assume3/TODO: type1 and type2 have the same type argument amount. + const isType1TypeLambdaInstance = isTypeLambdaInstance(type1); + const isType2TypeLambdaInstance = isTypeLambdaInstance(type2); + if(!isType1TypeLambdaInstance && !isType2TypeLambdaInstance){ + return isInheritance(type1, type2); + }else if(isType1TypeLambdaInstance != isType2TypeLambdaInstance){ + reportError(); + return false; + }else{ + const isInheritance = isInheritance(type1, type2); + if(!isInheritance) + // report error? + return false; + const variances[] = gotVariance(type1,type2); // maybe we do not need pass both of these two. Here is just a placeHolder. + for(let i = 0; i< variances.lenght; ++i){ + const v = variances[i]; + const parameter1 = gettypeParameter(type1, i); + const parameter2 = gettypeParameter(type2, i); + if(isBiVariance(v)){ + result = isTypeLessThan(type1, type2) || isTypeLessThan(type1, type2); + if(result === false){ + return result; + } + }else... + } + } +} + +// We assume all Types have been resolved. `resolved` here means typeParameter is replaced with actual typeArgument when check constraint +isTypeLambdaLessThan(Type A, Type B){ + // some assumptions, similar to isProperTypeLessThan + if(isTypeArgumentA(A) && isTypeParameter(B)){ + var typeLambdaDeclarationType_A = getDeclarationTypeOfTypeLambdaInstance(A); + var typeParameters_A = getTypeParametersOfTypeParameter(typeLambdaDeclarationType_A); + var typeParameters_B = getTypeParametersOfTypeParameter(typeLambdaDeclarationType_B); + if(typeParameters_A.length == typeParameters_B.length){reportError("kind not match");return false;} + // type parameter constraint is cotravariance + for(let i =0;i extends Set, X> + ``` + +1. checker + - constraints check valid rules(done) + - resolve type parameter with type arguments + - express hk constraint + - Error message and error conditions + - compatibility, what about infer and conditional? + +2. transformer + - emit hk type parameters correctly + +3. IDE support + - quick info + - how to express hk constraints? + - auto complete + +# Mapper + +For Generic, mapper is a simple and effective way. + +``` ts +interface Generic{ + +} +const foo: Generic; + foo. +// ^ here, this `Generic` object got the mapper. +``` + +But for hk, it is not that good. + +``` ts +interface Functor1, U>{ + a:Generic +} + +const foo: Functor1 +// ^ here, this got the mapper Generic --> Set, U --> number +``` +So, how `a` get the correct type? + +mapping recursively is a direct idea. like DFS, if it could be mapped, then map. each time go up, if up or bottom is mapped, create a new object. + +But let us see the real `higher kinded` + +``` ts +interface HKT3>, Generic2, Generic3, V>{ + a: Functor + b: Functor + xxx: Set + c: Generic2> // mapper U to what? + d: Generic3> // map W to Generic2 + e: Functor> // This would be an error, kind not match! But we could still ask: map Generic to what? +} + +const foo: HKT3 // check whether these type argument meet constraints; Do we need to initiate the type here? or it could be lazyed? +foo.a; // +foo.b; +``` + diff --git a/src/HKT_Cases.md b/src/HKT_Cases.md new file mode 100644 index 0000000000000..a8ff06bfeb6c1 --- /dev/null +++ b/src/HKT_Cases.md @@ -0,0 +1,329 @@ + +``` ts +class MySet extends Set { +} + +class MySet2 extends Set { +} + +// interface HKT extends MySet> extends Monod < MySet >> extends AnotherHKT < Functor2 > +// { +// HKT#Functor2: ; +// HKT#Functor2#Generic: ; +// HKT#Functor2#Generic#T: ; +// } + +interface HKT1 extends Set> extends HKT1_Concentrate{} + +interface HKT1>{ + f1(para:Generic){} // --> create Mapper{T-->U}, check constraint for T, instance_T(U) is U, pass! + f2(para:Generic){} // --> create Mapper{T-->int}, check constraint for T, instance_T(int) is not U, fail! + f3(para:Generic){} // --> create Mapper{T-->int}, check constraint for T, instance_T(string) is U, pass! +} // allowed +HKT1; // --> create Mapper{U-->number,Generic-->Set}, check constraint for U and Generic(No constraint) + // If no error, Merge Mapper, Mapper for `` is {U-->number,Generic-->Set,T-->U} + +interface HKT1 extends Set>{ + // check constraint declaration: whether Set is proper Set, that is to say, check U meet the constraint in Set. + // check typeParameter and constraint kind: the kind of constraint must be the same with typeparameter. The kind in here means ((*->*)->(*->*))->*, not just proper, one or two. + + f1(para:Generic){} // --> create Mapper{T-->U}, check typeParameter constraint for T, instance_T(U) is U, pass! + f2(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(int) is not U, fail! + f3(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(string) is U, pass! +} // allowed + +HKT1; // --> create Mapper{U-->number,Generic-->Set}, check constraint for U(wrong), instance_Generic(Set) is Set, pass! + // If no error, Merge Mapper, Mapper for `` is {U-->number,Generic-->Set,T-->U} + +interface HKT1 extends (Set|Array)>{ + // check constraint declaration: whether Set is proper Set, that is to say, check U1 meet the constraint in Set and U2 meet the constraint in Array. + // check typeParameter and constraint kind: the kind of constraint must be the same with typeparameter. The kind in here means ((*->*)->(*->*))->*, not just proper, one or two. + + f1(para:Generic){} // --> create Mapper{T-->U}, check typeParameter constraint for T, instance_T(U) is U, pass! + f1_2(para:Generic){} // --> create Mapper{T-->U}, check typeParameter constraint for T, instance_T(U) is U, pass! + f2(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(int) is not U, fail! + f3(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(string) is U, pass! +} // allowed +HKT1; // --> create Mapper{U-->number,Generic-->Set}, check constraint for U(wrong), instance_Generic(Set) is Set, pass! + // If no error, Merge Mapper, Mapper for `` is {U-->number,Generic-->Set,T-->U} + +interface HKT1 extends (Set|&Array)>{ + // check constraint declaration: whether Set is proper Set, that is to say, check U1 meet the constraint in Set and U2 meet the constraint in Array. + // check typeParameter and constraint kind: the kind of constraint must be the same with typeparameter. The kind in here means ((*->*)->(*->*))->*, not just proper, one or two. + f1(para:Generic){} // --> create Mapper{T-->U}, check typeParameter constraint for T, instance_T(U1) is U, pass! + f1_2(para:Generic){} // --> create Mapper{T-->U}, check typeParameter constraint for T, instance_T(U) is U, pass! + f2(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(int) is not U, fail! + f3(para:Generic){} // --> create Mapper{T-->int}, check typeParameter constraint for T, instance_T(string) is U, pass! +} // allowed +HKT1; // --> create Mapper{U-->number,Generic-->Set}, check constraint for U(wrong), instance_Generic(Set) is Set, pass! + // If no error, Merge Mapper, Mapper for `` is {U-->number,Generic-->Set,T-->U} + + + +interface HKT1 extends Set> extends HKT1_Concentrate{} +// error ^^^ expected a one kind type, but here is proper type + +interface HKT1 extends Set> extends HKT1_Concentrate{} + + +interface HKT1 extends Set> extends HKT1_Concentrate{} + +interface HKT1 extends Set> extends HKT1_Concentrate{ + +} +HKT1; // --> create Mapper{U-->string, Generic-->Set} check constraint for U, instance_U(string) is string, + +interface HKT2 extends MySet> extends Monod> extends AnotherHKT{ + f(para1: ) +} + +interface HKT extends MySet> extends Monod> extends AnotherHKT +{ + Functor2 + HKT#Functor2: ; + HKT#Functor2#Generic: ; + HKT#Functor2#Generic#T: ; +} + +// T<:A, upper bound, T is the subtype of A + +interface Type { }; + +interface Lambda { + parameterCount: number; + // If it is undefined, it is not explictly declared. Try to infer it then put it back. Or we could just add another property like resolvedParameterVariances + parameterVariances: VarianceState | undefined[]; + parameterUpperBounds: Type|Lambda[]; // Or just constraint. + parameterKind: Lambda[];// proper type is 0 kind. + applyUpperBounds: Type|Lambda; +} + +enum VarianceState { + Invariance = 0, + Covariance = 1 << 0, + Contravariance = 1 << 1, + Bivariance = Covariance | Contravariance +} +// Merge TypeMapper until it could get the final one. When merge conflict, throw error. +// If A is the subtype of B, A is `smaller` than B. + +// NOTE +// 1. when using in TypeParameters, `extends` is constraint. And when using outside, `extends` is inheritance. + + +// Problem +// 1. Union Type and Intersection Type +// This is similar to inheritance condition, here is an example: +// interface HKT1 extends (Set|&Array)>{ +// f1(para:Generic){} +// f1_2(para:Generic){} +// f1_3(para:Generic){} +// f2(para:Generic){} +// f3(para:Generic){} +// } +// Here is a big problem: which function is allowed? +// It seems the judgement have to be delayed the instance. Some instance could use part of the functions while others not. +// But this looks wired. Perhaps this is not that wired if we have one more keyword to declare we not check the functions without instances? +``` + +### scala example + +``` scala +object HelloWorld { + def main(args: Array[String]) { + var q: List[Int] = List(1, 2, 3, 4) + var w: Array[Boolean] = Array(true) + var t = getData(q,q) + } + def getData1[T<:Int,U<:Int,C[X<:Int]<:List[_]](a:C[T],b:C[U]) = 1/2 + def getData2[T,U,C[X],B[Q[_]]](a:C[T],b:C[U],c:B[C]) = 1/2 + def getData3[T<:String,C[X<:T]](a:C[T]) = 1/2 + def getData4[T<:String,C[X]<:List[_<:T]](a:C[T]) = 1/2 +} +class MyClass[T<:String,C[X<:T]]{ + def f[V<:T>](a:C[V])= 1/2 +} +``` + +### Checker + +when in type parameter declarations: +1. check constraint declaration itself: + - the declaration should be an instance type, its argument should meet the constraints it declared. + - constraint could not be a Union or Insection.(Maybe too strong, could be lossen by same type parameters) + +2. check typeParameter and constraint relation: + - kind: the kind of constraint must be the same with typeparameter. The kind in here means ((*->*)->(*->*))->*, not just proper, one or two. + +``` ts +interface HKT3 extends Map> extends SomeFunctor>{} +interface HKT3 extends Map> extends SomeFunctor>{} +interface HKT3 extends Map|Map2> extends SomeFunctor>{} +interface HKT3 extends Map|Map2> extends SomeFunctor>{} +// not works +interface HKT3 extends Set|Set2> extends SomeFunctor>{} +interface HKT3 extends Set|Set2> extends SomeFunctor>{} +// not works +``` + +start analytics +``` ts +class HKT, U extends T> { + f(p1: T, p2: U): number { + return 1; + } +} +const q = new HKT();// Error: number is not string // create Mapper{U-->} + +class HKT, U extends T> { + f1(p1: T, p2: U): T { + return p2; + } + f2(p1: T, p2: U): U { + return p2; + } +} +// always error + +class HKT, U extends T,X> { + f1(p1: T, p2: U): T { + return p2; + } + f2(p1: T, p2: U): U { + return p2; + } +} +const q = new HKT, Set,string>(); +const w = new HKT, MySet,string>(); + +// (*, *->*) -> * +interface HKT2>{ + f1 (para1:Generic){} // Should error, V does not have upper bound T. Mapper{Generic-->} + f2(para1:Generic){} // Mapper{Generic-->} +} + +interface SomeFunctor>{ + sf(parameter1: G) +} + +// (*, (*->*)->*) -> * +interface HKT3 extends Set> extends SomeFunctor>{ + f(parameter1: Functor){} //Mapper{Generic-->Set, } +} +HKT3 // Mapper{U-->int, Functor-->SomeFunctor} +``` + + +``` scala +class SomeFunctor[G[GU<:String]<:List[_<:String]]{ +// ^ here is an anoymous type parameter. +// SomeFunctor[Anonymous1<:String, G[GU<:String>]<:List[Anonymous1]]{ + def f(para1:G[String]) = 1 +} +class HKT3[U,Functor[Generic[T]] <: SomeFunctor[Generic]]{ +// error: Type argument Generic does not conform to upper bound [GU <: String] =>> List[? <: String] + def f2(para2:Functor[List])=1 +} +// ------ +class SomeFunctor[G[GU<:String]]{ + def f(para1:G[String]) = 1 +} +class HKT3[U,Functor[Generic[T]] <: SomeFunctor[Generic]]{ + def f2(para2:Functor[List])=1 +} +// ------- +class SomeFunctor[G[GU<:String]<:List[GU]]{ + def f(para1:G[String]) = 1 +} + +class HKT3[U,Functor[Generic[T<:String]<:List[_<:String]] <: SomeFunctor[Generic]]{ +// class HKT3[U,Functor[Generic[T<:String]<:List[T]] <: SomeFunctor[Generic]]{ this pass well + // error: Type argument Generic does not conform to upper bound [GU <: String] =>> List[GU] + def f2(para2:Functor[List])=1 + // error: Type argument List does not conform to upper bound [T] =>> List[? <: String] +} +``` + +### Binder + +binder: + - Question1: type parameter scope. The type parameter declared in another type parameter could only be used in the constraint. + +``` ts +interface HKT3 extends Set> extends SomeFunctor>{} +// works, of course. +interface HKT3 extends Set> extends SomeFunctor>{} +// works, of course. +interface HKT3 extends Set> extends SomeFunctor>{} +// also works, at least for this case. +interface HKT3 extends Set> extends SomeFunctor>{} +// ^1 ^2 ^2 +// this is shadow or duplicated error? +// reference to Scala, this is shadowed. +``` + + + + + +### + +``` scala +// This is OK +object test1: + class FunctorImpl[Generic1[T] <: Iterable[T]]{} + class HKT3_1[Functor[Generic2[T] <: Set[T]]]{} + var h = new HKT3_1[FunctorImpl](); + +// This is has error +object test2: + class FunctorImpl[Generic1[T] <: Iterable[T]]{} + class HKT3_1[Functor[Generic2[T <: String] <: Set[T]]]{} + var h = new HKT3_1[FunctorImpl](); // Error: Type argument FunctorImpl does not conform to upper bound [Generic2[T] <: Set[T]] =>> Any + +[Generic2[T<:String]<:Set[T]] = [Generic1[T] <: Iterable[T]] + +Explanation +=========== + +I tried to show that + test2.FunctorImpl +conforms to + [Generic2[T] <: Set[T]] =>> Any +but the comparison trace ended with `false`: + + ==> test2.FunctorImpl <: [Generic2[T] <: Set[T]] =>> Any + ==> test2.FunctorImpl <: [Generic2[T] <: Set[T]] =>> Any (recurring) + ==> type bounds [[T] <: Set[T]] <: type bounds [[T] <: Iterable[T]] + ==> type bounds [[T] <: Set[T]] <: type bounds [[T] <: Iterable[T]] (recurring) + ==> [T <: String] =>> Set[T] <: [U]=>>Iterable[U] + ==> [T <: String] =>> Set[T] <: [U]=>>Iterable[U] (recurring) + ==> type bounds [] <: type bounds [ <: String] + ==> type bounds [] <: type bounds [ <: String] (recurring) + ==> Any <: String + ==> Any <: String (recurring) + ==> Any <: String (recurring) + <== Any <: String (recurring) = false + <== Any <: String (recurring) = false + <== Any <: String = false + <== type bounds [] <: type bounds [ <: String] (recurring) = false + <== type bounds [] <: type bounds [ <: String] = false + <== [T <: String] =>> Set[T] <: Iterable (recurring) = false + <== [T <: String] =>> Set[T] <: Iterable = false + <== type bounds [[T] <: Set[T]] <: type bounds [[T] <: Iterable[T]] (recurring) = false + <== type bounds [[T] <: Set[T]] <: type bounds [[T] <: Iterable[T]] = false + <== test2.FunctorImpl <: [Generic2[T] <: Set[T]] =>> Any (recurring) = false + <== test2.FunctorImpl <: [Generic2[T] <: Set[T]] =>> Any = false + +The tests were made under the empty constraint +``` \ No newline at end of file diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index aec962016a280..1ebf043ec5b78 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1754,6 +1754,7 @@ namespace ts { case SyntaxKind.ModuleDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.MappedType: + case SyntaxKind.TypeParameter: // Not sure whether this is proper. return ContainerFlags.IsContainer | ContainerFlags.HasLocals; case SyntaxKind.SourceFile: @@ -1875,6 +1876,7 @@ namespace ts { case SyntaxKind.JSDocCallbackTag: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.MappedType: + case SyntaxKind.TypeParameter: // HKT // All the children of these container types are never visible through another // symbol (i.e. through another symbol's 'exports' or 'members'). Instead, // they're only accessed 'lexically' (i.e. from code that exists underneath diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2e1ed38efe01d..3c45825518a4d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1811,6 +1811,11 @@ namespace ts { } } break; + case SyntaxKind.TypeParameter: + if (location.locals && (result = lookup(location.locals, name, meaning & SymbolFlags.Type))) { + break loop; + } + break; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: @@ -3747,6 +3752,12 @@ namespace ts { return type; } + function createTypeLambda(symbol?: Symbol) { + const type = createType(TypeFlags.TypeLambda); + if (symbol) type.symbol = symbol; + return type; + } + // A reserved member name starts with two underscores, but the third character cannot be an underscore, // @, or #. A third underscore indicates an escaped form of an identifier that started // with at least two underscores. The @ character indicates that the name is denoted by a well known ES @@ -8834,32 +8845,25 @@ namespace ts { function getTypeOfSymbol(symbol: Symbol): Type { const checkFlags = getCheckFlags(symbol); - if (checkFlags & CheckFlags.DeferredType) { - return getTypeOfSymbolWithDeferredType(symbol); - } - if (checkFlags & CheckFlags.Instantiated) { - return getTypeOfInstantiatedSymbol(symbol); - } - if (checkFlags & CheckFlags.Mapped) { - return getTypeOfMappedSymbol(symbol as MappedSymbol); - } - if (checkFlags & CheckFlags.ReverseMapped) { - return getTypeOfReverseMappedSymbol(symbol as ReverseMappedSymbol); - } - if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { - return getTypeOfVariableOrParameterOrProperty(symbol); - } - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { - return getTypeOfFuncClassEnumModule(symbol); - } - if (symbol.flags & SymbolFlags.EnumMember) { - return getTypeOfEnumMember(symbol); - } - if (symbol.flags & SymbolFlags.Accessor) { - return getTypeOfAccessors(symbol); - } - if (symbol.flags & SymbolFlags.Alias) { - return getTypeOfAlias(symbol); + switch (true) { + case !!(checkFlags & CheckFlags.DeferredType): + return getTypeOfSymbolWithDeferredType(symbol); + case !!(checkFlags & CheckFlags.Instantiated): + return getTypeOfInstantiatedSymbol(symbol); + case !!(checkFlags & CheckFlags.Mapped): + return getTypeOfMappedSymbol(symbol as MappedSymbol); + case !!(checkFlags & CheckFlags.ReverseMapped): + return getTypeOfReverseMappedSymbol(symbol as ReverseMappedSymbol); + case !!(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)): + return getTypeOfVariableOrParameterOrProperty(symbol); + case !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)): + return getTypeOfFuncClassEnumModule(symbol); + case !!(symbol.flags & SymbolFlags.EnumMember): + return getTypeOfEnumMember(symbol); + case !!(symbol.flags & SymbolFlags.Accessor): + return getTypeOfAccessors(symbol); + case !!(symbol.flags & SymbolFlags.Alias): + return getTypeOfAlias(symbol); } return errorType; } @@ -9456,7 +9460,21 @@ namespace ts { function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter { const links = getSymbolLinks(symbol); - return links.declaredType || (links.declaredType = createTypeParameter(symbol)); + if (!links.declaredType) { + const tmp = createTypeParameter(symbol); + + const index = 0;// or it should be symbol.declarations.length-1 ? + const declration = symbol.declarations[index]; + // this means it is typeConstructor. + if (isTypeParameterDeclaration(declration) && declration.typeParameters && declration.typeParameters.length > 0) { + tmp.flags |= TypeFlags.TypeConstructorDeclaration; + // This line is important, which combines Node and Type. + // for now Node.paras is not used but its length. So constrait is not used for now. + (tmp).tParams = declration.typeParameters.length; + } + links.declaredType = tmp; + } + return links.declaredType; } function getDeclaredTypeOfAlias(symbol: Symbol): Type { @@ -12116,6 +12134,228 @@ namespace ts { return length(type.target.typeParameters); } + function isTypeLambda(t: Type): t is TypeLambda { + console.log(t); + throw new Error("no implement"); + } + + // define <: on ProperType + // true if `pt1` <: `pt2` + // This is wrong. Should use existing function. But this is easy to be checked as prototype. + function isProperTypeLessThan(pt1: ProperType, pt2: ProperType): boolean { + return checkTypeRelatedTo(pt1, pt2, assignableRelation, undefined); + // // ObjectType + // if (pt1.flags & TypeFlags.Object && pt2.flags & TypeFlags.Object) { + // // like Set, Functor + // if ((pt1).objectFlags & ObjectFlags.Reference && (pt2).objectFlags & ObjectFlags.Reference) { + // getBaseConstructorTypeOfClass() + // // Should we check constraint? + // // const tmp1 = convertTypeToTypelambda((pt1).target); + // // const tmp2 = convertTypeToTypelambda((pt1).target); + // // let res = isTypeLambdaLessThan(tmp1, tmp2); + // if (!res) return false; + // const typeArguments1 = getTypeArguments(pt1); + // const typeArguments2 = getTypeArguments(pt2); + // } + // else {debugger;} + // } + // else if () { + // } + // return false; + } + + /** + * define <: on TypeLambda + * TL1 = [X >: L1 <: U1] =>> R1 + * TL2 = [X >: L2 <: U2] =>> R2 + * TL1 <: TL2 if + * - L2..U2 is more strict. (i.e. L1 <: L2 and U2 <: U1) + * - R1 <: R2 + * @param tl1 + * @param tl2 + * @returns tl1 <: tl2 + */ + // @ts-ignore + function isTypeLambdaLessThan(tl1: TypeLambda, tl2: TypeLambda): boolean { + Debug.assert(tl1.paramInfos.length === tl1.paramInfos.length, "kind must match"); + const lengthOfTypeParameters = tl1.paramInfos.length; + // parameters are contravariance + for (let i = 0; i < lengthOfTypeParameters; i++) { + const constraint1 = tl1.paramInfos[i].upperBound ?? anyType; + const constraint2 = tl2.paramInfos[i].upperBound ?? anyType; + const isTypeLamnda1 = isTypeLambda(constraint1); + const isTypeLamnda2 = isTypeLambda(constraint2); + Debug.assert(isTypeLamnda1 === isTypeLamnda2, "kind must match"); + let res: boolean; + if (isTypeLambda(constraint1) && isTypeLambda(constraint2)) { + res = isTypeLambdaLessThan(constraint2, constraint1); + } + else { + res = isProperTypeLessThan(constraint2, constraint1); + } + if (!res) return false; + } + // apply are covariance + const appliedType1 = tl1.resType ?? anyType; + const appliedType2 = tl2.resType ?? anyType; + const res = isProperTypeLessThan(appliedType1, appliedType2); + return res; + } + + // @ts-ignore + function convertTypeToTypelambda(t: TypeConstructorPolymorphismDeclaration | InterfaceType): TypeLambda { + // TODO (song): cache it + Debug.assert(t.typeParameters && t.typeParameters.length > 0); + const typeLambda = createTypeLambda(t.symbol); + + // if it is Class or Interface + if (t.flags & TypeFlags.Object && (t).objectFlags & ObjectFlags.ClassOrInterface) { + typeLambda.paramInfos = t.typeParameters.map(convertTypeParameter); + typeLambda.resType = t; + } + // if it is HK type parameter + else if(isTypeParameterTypeConstructorDeclaration(t)){ + typeLambda.paramInfos = t.typeParameters.map(convertTypeParameter); + typeLambda.resType = getConstraintFromTypeParameter(t); + } + return typeLambda; + + // F[X] = R + // F = [X] ==> R + + // TL1 = [X >: L1 <: U1] =>> R1 + + // [F[X] <: Coll[X]] + // [F >: Nothing <: [X] =>> Coll[X]] + // [X <: R] + // To TypeLambda or ProperType + function convertTypeParameter(typeParameter: TypeParameter): TypeLambdaParameterInfo { + // typeParameter contains typeparameter, its kind is more than zero. + // Convert it to TypeLambda. + let res: TypeLambdaParameterInfo; + if (isTypeParameterTypeConstructorDeclaration(typeParameter)) { + res = { + typeRef: typeParameter, + upperBound: convertTypeToTypelambda(typeParameter), + variance: VarianceFlags.Bivariant + }; + } + // it is just a proper type, zero kind. + else { + res = { + typeRef: typeParameter, + // any type is the top upper bound. + upperBound: getConstraintFromTypeParameter(typeParameter) ?? anyType, + // TODO (song): variance marker? or infer from structure? + variance: VarianceFlags.Bivariant + }; + } + return res; + } + } + + // @ts-ignore + function applyTypeLambdaWithTypeArguments(tl: TypeLambda, typearguments: (TypeLambda | ProperType)[]): ProperType { + + } + + // interface Functor[Generic[T <: U] <: Set[U], U] + // Functor[List, number] + // In this case, when check whether List <: Functor#Generic, we need to replace U with number first + // So we should + // 1. create a Mapper + // 2. instanitatedTL = instanitateTypeLambdaWithMapper(Generic, Mapper) + // 3. isTypeLambdaLessThan(List, instanitatedTL) + // @ts-ignore + function instanitateTypeLambdaWithMapper(){ + + } + + /** + * we assueme that typeArgument must be a TypeReference TypeArgument, which means it get the typeConstructor parent which take it as a typeArgument. + */ + function isTypeConstructorArgumentValidInTypeConstructorPolymorisic(typeArgument: TypeReferenceNode) { + // Question! should we assume typeArgument always does not have any type argument? + + const parentNode = typeArgument.parent; + // I am not sure whether the parent could have the typeArgument, maybe the grandparent? + if (!isTypeReferenceNode(parentNode)) { + debugger; + return false; + } + const argumentIndex = parentNode.typeArguments?.findIndex(ta => ta === typeArgument); + if (argumentIndex === undefined || argumentIndex < 0) { + // never happens. If code runs here, it means we find the parent wrongly or we do not find the proper argument node(it might have typecasting or sth else?) + return false; + } + + const typeParametersOfArgument = getTypeParameterOfTypeConstructorNode(typeArgument); + + const typeParameterIndex = argumentIndex; + const typeParameters = getTypeParameterOfTypeConstructorNode(parentNode); + if (!typeParameters) { + return false; + } + const correspondTypeParameter = typeParameters[typeParameterIndex]; + if (!isTypeParameterTypeConstructorDeclaration(correspondTypeParameter)) { + /** + * interface G{} + * interface HKT>{} + * v: G <-- the inner G is a typeConstructor, but the first type parameter of outter G is not type constructor polymorphism. + */ + const diag = Diagnostics.Proper_Polymorphism_type_parameter_0_could_not_accept_Generic_type_1; + const typeConstructorPolymorphismStr = typeToString(correspondTypeParameter, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + const genericString = entityNameToString(typeArgument.typeName); + error(typeArgument, diag, typeConstructorPolymorphismStr, genericString); + return false; + } + + if (correspondTypeParameter.tParams !== length(typeParametersOfArgument)) { + /** + * interface G{} + * interface HKT>{} + * v: HKT <-- G has two type parameters but the type constructor polymorphism Container only accept one type parameter. + */ + const diag = Diagnostics.When_Generic_type_0_is_used_as_type_argument_its_type_parameter_must_match_type_constructor_polymorphism_1; + const typeConstructorPolymorphismStr = typeToString(correspondTypeParameter, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + const genericString = entityNameToString(typeArgument.typeName); + error(typeArgument, diag, genericString, typeConstructorPolymorphismStr); + return false; + } + + return true; + + function getTypeParameterOfTypeConstructorNode(typeConstructor: TypeReferenceNode) { + const symbol = getSymbolOfTypeConstructorTypeReference(typeConstructor); + if (!symbol) { + return undefined; + } + const typeParameters = getTypeParametersFromTypeConstructorSymbol(symbol); + return typeParameters; + } + + // or this one? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias + function getTypeParametersFromTypeConstructorSymbol(symbol: Symbol) { + const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); // this has work even in TypeAlias condition -- it give typeParameters value if there is not. + if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + const typeParameters = (type).localTypeParameters; + return typeParameters; + } + if (symbol.flags & SymbolFlags.TypeAlias) { + const links = getSymbolLinks(symbol); + const typeParameters = links.typeParameters; + return typeParameters; + } + } + + // I wish the symbol should be a interface/class/alias + // the typeconstructor parameter is not included. + function getSymbolOfTypeConstructorTypeReference(typeConstructor: TypeReferenceNode): Symbol | undefined { + const meaning = SymbolFlags.Type; + return resolveTypeReferenceName(getTypeReferenceName(typeConstructor), meaning); + } + } + /** * Get type from type-reference that reference to class or interface @@ -12128,25 +12368,33 @@ namespace ts { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { - const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); - const diag = minTypeArgumentCount === typeParameters.length ? - missingAugmentsTag ? - Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_1_type_argument_s : - missingAugmentsTag ? - Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; - - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); - if (!isJs) { - // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) - return errorType; + // type reference without typeArguments. Like Set, rather than Set + if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0 && isTypeConstructorArgumentValidInTypeConstructorPolymorisic(node)) { + (type).isConcentrateTypeConstructor = true; + // These are not well considered, just for passing test cases. + // Maybe all those code should be removed and written in other places. + } + else { + if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { + const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); + const diag = minTypeArgumentCount === typeParameters.length ? + missingAugmentsTag ? + Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : + Diagnostics.Generic_type_0_requires_1_type_argument_s : + missingAugmentsTag ? + Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : + Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; + + const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); + if (!isJs) { + // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) + return errorType; + } } } - if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(node, length(node.typeArguments) !== typeParameters.length)) { - return createDeferredTypeReference(type, node, /*mapper*/ undefined); + if (isTypeReferenceNode(node) && isDeferredTypeReferenceNode(node, length(node.typeArguments) !== typeParameters.length)) { + return createDeferredTypeReference(type, node, /*mapper*/ undefined); } // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters @@ -12183,6 +12431,11 @@ namespace ts { if (typeParameters) { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); + if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0 && isTypeConstructorArgumentValidInTypeConstructorPolymorisic(node)) { + (type).isConcentrateTypeConstructor = true; + (type).origionalTypeAliasSymbol = symbol; + return type; + } if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { error(node, minTypeArgumentCount === typeParameters.length ? @@ -12224,6 +12477,7 @@ namespace ts { } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { + // Debug.assert(isTypeReferenceNode(node)); if (symbol === unknownSymbol) { return errorType; } @@ -12237,7 +12491,26 @@ namespace ts { // Get type from reference to named type that cannot be generic (enum or type parameter) const res = tryGetDeclaredTypeOfSymbol(symbol); if (res) { - return checkNoTypeArguments(node, symbol) ? getRegularTypeOfLiteralType(res) : errorType; + /* + interface Itertable> { + filter(p: (x: T) => boolean): Container; + ^ this should not report as error. + } + */ + if (isTypeParameterTypeConstructorDeclaration(res)) { + if(node.typeArguments?.length !== res.tParams){ + //check whether type arguments match type parameters. + } + const typeConstructorInstance = createTypeParameter(symbol); + typeConstructorInstance.flags |= TypeFlags.TypeConstructorInstance; + (typeConstructorInstance).resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); + (typeConstructorInstance).origionalTypeConstructorDeclaration = res; + return typeConstructorInstance; + } + if (checkNoTypeArguments(node, symbol)) { + return getRegularTypeOfLiteralType(res); + } + return errorType; } if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { const jsdocType = getTypeFromJSDocValueReference(node, symbol); @@ -13843,6 +14116,14 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } + function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorPolymorphismDeclaration { + return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorDeclaration); + } + + function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorPolymorphismInstance { + return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorInstance); + } + function getSimplifiedType(type: Type, writing: boolean): Type { return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type, writing) : type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type, writing) : @@ -14820,7 +15101,7 @@ namespace ts { case TypeMapKind.Array: const sources = mapper.sources; const targets = mapper.targets; - for (let i = 0; i < sources.length; i++) { + for (let i = 0; i < sources.length; i++) { // we should check whether the generic and typeconstructor has the same parameters. Or here is too late, we should check when mapper is created. if (type === sources[i]) { return targets ? targets[i] : anyType; } @@ -14984,7 +15265,7 @@ namespace ts { // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. const combinedMapper = combineTypeMappers(type.mapper, mapper); - const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); + const typeArguments = map(typeParameters, t => instantiateTypeOfTypeParameter(t, combinedMapper)); //maybe this is instantiateType?Or instantiateTypeWorker? I just want to handle typeConstructor situation. const id = getTypeListId(typeArguments); let result = links.instantiations!.get(id); if (!result) { @@ -15001,7 +15282,7 @@ namespace ts { function maybeTypeParameterReference(node: Node) { return !(node.kind === SyntaxKind.QualifiedName || - node.parent.kind === SyntaxKind.TypeReference && (node.parent).typeArguments && node === (node.parent).typeName || + // node.parent.kind === SyntaxKind.TypeReference && (node.parent).typeArguments && node === (node.parent).typeName || // delete this line or add more constract. node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier); } @@ -15203,10 +15484,43 @@ namespace ts { return result; } + // this function is mainly for the change in function `getObjectTypeInstantiation`, another choice is written in the comment of that changed line. + function instantiateTypeOfTypeParameter(type: TypeParameter, mapper: TypeMapper): Type { + const flags = type.flags; + if (isTypeParameterTypeConstructorInstance(type)) { + debugger; + const origionalTypeConstructorParameter = type.origionalTypeConstructorDeclaration!; + const resolvedTypeConstructorParam = type.resolvedTypeConstructorParam; + const concentrateGenericType = getMappedType(origionalTypeConstructorParameter, mapper); + if (concentrateGenericType === origionalTypeConstructorParameter) { + debugger;//on which condition this would happen? + return origionalTypeConstructorParameter; + } + const newTypeArguments = instantiateTypes(resolvedTypeConstructorParam, mapper); + // concentrate type constructor is TypeAlias + if (!!concentrateGenericType.aliasSymbol) { + const tmpSymbol: Symbol = (concentrateGenericType).origionalTypeAliasSymbol; + return getTypeAliasInstantiation(tmpSymbol, newTypeArguments); + } + // concentrate type constructor is Object of Interface/Class + else { + return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); + } + } + else if (flags & TypeFlags.TypeConstructorDeclaration) { + // this is a demo implement, and not well considered. + // ATTENTION: this might cause error.(just guess, in which condition the declaration would be mapped?) + return getMappedType(type, mapper); + } + else { + return getMappedType(type, mapper); + } + } + function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { const flags = type.flags; if (flags & TypeFlags.TypeParameter) { - return getMappedType(type, mapper); + return instantiateTypeOfTypeParameter(type, mapper); } if (flags & TypeFlags.Object) { const objectFlags = (type).objectFlags; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9e53407c4373c..63627664c31cc 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3051,6 +3051,18 @@ "category": "Error", "code": 2795 }, + "Type Constructor Polymorphism type parameter {0} could not accept proper type {1}": { + "category": "Error", + "code": 2800 + }, + "Proper Polymorphism type parameter {0} could not accept Generic type {1} ": { + "category": "Error", + "code": 2801 + }, + "When Generic type {0} is used as type argument, its type parameter must match type constructor polymorphism {1}": { + "category": "Error", + "code": 2802 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 3d1b6fdb9a7d3..d2546f6dc3ad8 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1084,7 +1084,7 @@ namespace ts { // // @api - function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) { + function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode, tParams?: NodeArray) { const node = createBaseNamedDeclaration( SyntaxKind.TypeParameter, /*decorators*/ undefined, @@ -1094,6 +1094,7 @@ namespace ts { node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; + node.typeParameters = tParams; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a815a12db9a53..df22fda2c405a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -83,6 +83,7 @@ namespace ts { visitNode(cbNode, (node).right); case SyntaxKind.TypeParameter: return visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters)|| visitNode(cbNode, (node).constraint) || visitNode(cbNode, (node).default) || visitNode(cbNode, (node).expression); @@ -2464,7 +2465,15 @@ namespace ts { break; } } - + const res = createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0); + // Or we could add a nodeFlag, or we could add this code in each *parseTypeArguments* functions. + if (parsingContext | (1 << ParsingContext.TypeArguments)){ + forEach(res, (t) => { + if (isTypeReferenceNode(t)) { + t.isTypeArguments = true; + } + }); + } parsingContext = saveParsingContext; // Recording the trailing comma is deliberately done after the previous // loop, and not just if we see a list terminator. This is because the list @@ -2472,7 +2481,7 @@ namespace ts { // was a trailing comma. // Check if the last token was a comma. // Always preserve a trailing comma by marking it on the NodeArray - return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0); + return res; } function getExpectedCommaDiagnostic(kind: ParsingContext) { @@ -2870,6 +2879,11 @@ namespace ts { const name = parseIdentifier(); let constraint: TypeNode | undefined; let expression: Expression | undefined; + let tParams: NodeArray | undefined; + if (token() === SyntaxKind.LessThanToken) { + tParams = parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + if (parseOptional(SyntaxKind.ExtendsKeyword)) { // It's not uncommon for people to write improper constraints to a generic. If the // user writes a constraint that is an expression and not an actual type, then parse @@ -2891,7 +2905,7 @@ namespace ts { } const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; - const node = factory.createTypeParameterDeclaration(name, constraint, defaultType); + const node = factory.createTypeParameterDeclaration(name, constraint, defaultType, tParams); node.expression = expression; return finishNode(node, pos); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index fbf308707a10d..173329b5d08ea 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1202,6 +1202,9 @@ namespace ts { // For error recovery purposes. expression?: Expression; + + /** If this is not empty, it is a type constructor. So this might be considered as hkTypeParamDeclarations*/ + typeParameters?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { @@ -1523,6 +1526,7 @@ namespace ts { } export interface NodeWithTypeArguments extends TypeNode { + // undefined if no LessThanToken followed. readonly typeArguments?: NodeArray; } @@ -1531,6 +1535,8 @@ namespace ts { export interface TypeReferenceNode extends NodeWithTypeArguments { readonly kind: SyntaxKind.TypeReference; readonly typeName: EntityName; + //@internal + isTypeArguments: boolean; } export interface TypePredicateNode extends TypeNode { @@ -2790,6 +2796,7 @@ namespace ts { | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag + | TypeParameterDeclaration // HKT, an example: interface HKT3>>, parent of `Generic` is `Functor`. ; export interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer { @@ -4869,6 +4876,10 @@ namespace ts { Null = 1 << 16, Never = 1 << 17, // Never type TypeParameter = 1 << 18, // Type parameter + // @internal + TypeConstructorDeclaration = 1<< 29, // Type Constructor Declaration, this is an additional flag of TypeParameter. This should include the constraint and parameter constrait. + // @internal + TypeConstructorInstance = 1<< 30, // Type Constructor, this is an additional flag of TypeParameter. This should include the concentrate arguments(not mapped yet). Object = 1 << 19, // Object type Union = 1 << 20, // Union (T | U) Intersection = 1 << 21, // Intersection (T & U) @@ -4879,6 +4890,7 @@ namespace ts { NonPrimitive = 1 << 26, // intrinsic object type TemplateLiteral = 1 << 27, // Template literal type StringMapping = 1 << 28, // Uppercase/Lowercase type + TypeLambda = 1 << 31, // Type Lambda is very special, not sure. But I guess it could not be used with any other flags? So should it be a flag? /* @internal */ AnyOrUnknown = Any | Unknown, @@ -5317,6 +5329,48 @@ namespace ts { resolvedDefaultType?: Type; } + // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorDeclaration) + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter{ + /* @internal */ + tParams?: number; // Not allowed constraint for now, this might be a very complex feature. + typeParameters: TypeParameter[] | undefined; + // @override + constraint?: TypeLambda; + } + + // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorInstance) + export interface TypeConstructorPolymorphismInstance extends TypeParameter{ + /* @internal */ + resolvedTypeConstructorParam?: Type[]; + /* @internal */ + origionalTypeConstructorDeclaration?: TypeConstructorPolymorphismDeclaration; + } + + // One Type is ProperType if it is not a TypeLambda. e.g Set, Set>. + // However, Set depends, if it means the class, it is a type lambda(T is typeParameter), if it is a constraint, it is a proper type(T is a declared typeArgument). + /** + * interface MyGeneric exnteds Set{} + * ^ lambda ^ ^ both proper + * interface MyFunctor extends Set>{} + * ^ ^ both lambda ^ ^ both proper + */ + export interface ProperType extends Type { + } + + export interface TypeLambdaParameterInfo { + typeRef: Type; + upperBound?: TypeLambda | ProperType; + variance: VarianceFlags + } + + export interface TypeLambda extends Type { + resType?: ProperType; + paramInfos: TypeLambdaParameterInfo[]; + target: TypeLambda | TypeParameter | InterfaceType; + /* @internal true if any params and resType does not have typeParameter declared in the declared tree of origional target */ + isFullyinstantiated: boolean; + } + // Indexed access types (TypeFlags.IndexedAccess) // Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable export interface IndexedAccessType extends InstantiableType { @@ -6733,7 +6787,7 @@ namespace ts { // Signature elements // - createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; + createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode, tParams?: NodeArray): TypeParameterDeclaration; updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 973528096a1f3..bc7f3dcd8b0c8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -814,6 +814,7 @@ namespace ts { case SyntaxKind.SetAccessor: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: + case SyntaxKind.TypeParameter: return true; default: assertType(node); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 2b5ca8d1f18f6..a20090bcf7838 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -670,6 +670,7 @@ declare namespace ts { readonly constraint?: TypeNode; readonly default?: TypeNode; expression?: Expression; + tParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { readonly kind: SignatureDeclaration["kind"]; @@ -2619,6 +2620,10 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter { + } + export interface TypeConstructorPolymorphismInstance extends TypeParameter { + } export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; @@ -3192,7 +3197,7 @@ declare namespace ts { updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName; createComputedPropertyName(expression: Expression): ComputedPropertyName; updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName; - createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; + createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode, tParams?: NodeArray): TypeParameterDeclaration; updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; @@ -10094,7 +10099,7 @@ declare namespace ts { /** @deprecated Use `factory.updateComputedPropertyName` or the factory supplied by your transformation context instead. */ const updateComputedPropertyName: (node: ComputedPropertyName, expression: Expression) => ComputedPropertyName; /** @deprecated Use `factory.createTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ - const createTypeParameterDeclaration: (name: string | Identifier, constraint?: TypeNode | undefined, defaultType?: TypeNode | undefined) => TypeParameterDeclaration; + const createTypeParameterDeclaration: (name: string | Identifier, constraint?: TypeNode | undefined, defaultType?: TypeNode | undefined, tParams?: NodeArray | undefined) => TypeParameterDeclaration; /** @deprecated Use `factory.updateTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ const updateTypeParameterDeclaration: (node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) => TypeParameterDeclaration; /** @deprecated Use `factory.createParameterDeclaration` or the factory supplied by your transformation context instead. */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 0df67772e6e09..ef4a79593e3ff 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -670,6 +670,7 @@ declare namespace ts { readonly constraint?: TypeNode; readonly default?: TypeNode; expression?: Expression; + tParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { readonly kind: SignatureDeclaration["kind"]; @@ -2619,6 +2620,10 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter { + } + export interface TypeConstructorPolymorphismInstance extends TypeParameter { + } export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; @@ -3192,7 +3197,7 @@ declare namespace ts { updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName; createComputedPropertyName(expression: Expression): ComputedPropertyName; updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName; - createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; + createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode, tParams?: NodeArray): TypeParameterDeclaration; updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; @@ -6468,7 +6473,7 @@ declare namespace ts { /** @deprecated Use `factory.updateComputedPropertyName` or the factory supplied by your transformation context instead. */ const updateComputedPropertyName: (node: ComputedPropertyName, expression: Expression) => ComputedPropertyName; /** @deprecated Use `factory.createTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ - const createTypeParameterDeclaration: (name: string | Identifier, constraint?: TypeNode | undefined, defaultType?: TypeNode | undefined) => TypeParameterDeclaration; + const createTypeParameterDeclaration: (name: string | Identifier, constraint?: TypeNode | undefined, defaultType?: TypeNode | undefined, tParams?: NodeArray | undefined) => TypeParameterDeclaration; /** @deprecated Use `factory.updateTypeParameterDeclaration` or the factory supplied by your transformation context instead. */ const updateTypeParameterDeclaration: (node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) => TypeParameterDeclaration; /** @deprecated Use `factory.createParameterDeclaration` or the factory supplied by your transformation context instead. */ diff --git a/tests/baselines/reference/genericInterfacesWithoutTypeArguments.errors.txt b/tests/baselines/reference/genericInterfacesWithoutTypeArguments.errors.txt index b81230b440db2..42a56cb588320 100644 --- a/tests/baselines/reference/genericInterfacesWithoutTypeArguments.errors.txt +++ b/tests/baselines/reference/genericInterfacesWithoutTypeArguments.errors.txt @@ -1,8 +1,9 @@ tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts(3,8): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts(4,10): error TS2314: Generic type 'I' requires 1 type argument(s). +tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts(4,10): error TS2801: Proper Polymorphism type parameter T could not accept Generic type I -==== tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts (2 errors) ==== +==== tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts (3 errors) ==== interface I { } class C { } var i: I; @@ -11,4 +12,6 @@ tests/cases/compiler/genericInterfacesWithoutTypeArguments.ts(4,10): error TS231 var c: C; ~ !!! error TS2314: Generic type 'I' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type I \ No newline at end of file diff --git a/tests/baselines/reference/genericTypeReferencesRequireTypeArgs.errors.txt b/tests/baselines/reference/genericTypeReferencesRequireTypeArgs.errors.txt index 224e5e038da66..9ffc73a39918c 100644 --- a/tests/baselines/reference/genericTypeReferencesRequireTypeArgs.errors.txt +++ b/tests/baselines/reference/genericTypeReferencesRequireTypeArgs.errors.txt @@ -1,10 +1,12 @@ tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(7,9): error TS2314: Generic type 'C' requires 1 type argument(s). tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(8,9): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(9,11): error TS2314: Generic type 'I' requires 1 type argument(s). +tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(9,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type I tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(10,11): error TS2314: Generic type 'C' requires 1 type argument(s). +tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(10,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type C -==== tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts (4 errors) ==== +==== tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts (6 errors) ==== class C { foo(): T { return null } } @@ -20,7 +22,11 @@ tests/cases/compiler/genericTypeReferencesRequireTypeArgs.ts(10,11): error TS231 var c2: C; // should be an error ~ !!! error TS2314: Generic type 'I' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type I var i2: I; // should be an error ~ !!! error TS2314: Generic type 'C' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type C \ No newline at end of file diff --git a/tests/baselines/reference/genericsWithoutTypeParameters1.errors.txt b/tests/baselines/reference/genericsWithoutTypeParameters1.errors.txt index c1382788bebd6..c408fb8b3623b 100644 --- a/tests/baselines/reference/genericsWithoutTypeParameters1.errors.txt +++ b/tests/baselines/reference/genericsWithoutTypeParameters1.errors.txt @@ -1,11 +1,15 @@ tests/cases/compiler/genericsWithoutTypeParameters1.ts(9,9): error TS2314: Generic type 'C' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(10,9): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(11,11): error TS2314: Generic type 'I' requires 1 type argument(s). +tests/cases/compiler/genericsWithoutTypeParameters1.ts(11,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type I tests/cases/compiler/genericsWithoutTypeParameters1.ts(12,11): error TS2314: Generic type 'C' requires 1 type argument(s). +tests/cases/compiler/genericsWithoutTypeParameters1.ts(12,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type C tests/cases/compiler/genericsWithoutTypeParameters1.ts(14,17): error TS2314: Generic type 'C' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(14,23): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(15,20): error TS2314: Generic type 'I' requires 1 type argument(s). +tests/cases/compiler/genericsWithoutTypeParameters1.ts(15,20): error TS2801: Proper Polymorphism type parameter T could not accept Generic type I tests/cases/compiler/genericsWithoutTypeParameters1.ts(15,29): error TS2314: Generic type 'C' requires 1 type argument(s). +tests/cases/compiler/genericsWithoutTypeParameters1.ts(15,29): error TS2801: Proper Polymorphism type parameter T could not accept Generic type C tests/cases/compiler/genericsWithoutTypeParameters1.ts(17,13): error TS2314: Generic type 'C' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(18,14): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/compiler/genericsWithoutTypeParameters1.ts(21,8): error TS2314: Generic type 'C' requires 1 type argument(s). @@ -15,7 +19,7 @@ tests/cases/compiler/genericsWithoutTypeParameters1.ts(27,8): error TS2314: Gene tests/cases/compiler/genericsWithoutTypeParameters1.ts(31,22): error TS2314: Generic type 'A' requires 1 type argument(s). -==== tests/cases/compiler/genericsWithoutTypeParameters1.ts (15 errors) ==== +==== tests/cases/compiler/genericsWithoutTypeParameters1.ts (19 errors) ==== class C { foo(): T { return null } } @@ -33,9 +37,13 @@ tests/cases/compiler/genericsWithoutTypeParameters1.ts(31,22): error TS2314: Gen var c2: C; ~ !!! error TS2314: Generic type 'I' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type I var i2: I; ~ !!! error TS2314: Generic type 'C' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type C function foo(x: C, y: I) { } ~ @@ -45,8 +53,12 @@ tests/cases/compiler/genericsWithoutTypeParameters1.ts(31,22): error TS2314: Gen function foo2(x: C, y: I) { } ~ !!! error TS2314: Generic type 'I' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type I ~ !!! error TS2314: Generic type 'C' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type C var x: { a: C } = { a: new C() }; ~ diff --git a/tests/baselines/reference/infiniteConstraints.errors.txt b/tests/baselines/reference/infiniteConstraints.errors.txt index 2548b00f04436..042373c1314fb 100644 --- a/tests/baselines/reference/infiniteConstraints.errors.txt +++ b/tests/baselines/reference/infiniteConstraints.errors.txt @@ -1,11 +1,13 @@ tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' cannot be used to index type 'B[Exclude]'. +tests/cases/compiler/infiniteConstraints.ts(21,35): error TS2801: Proper Polymorphism type parameter U could not accept Generic type Value +tests/cases/compiler/infiniteConstraints.ts(21,89): error TS2801: Proper Polymorphism type parameter U could not accept Generic type Value tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'. tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'. tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'. tests/cases/compiler/infiniteConstraints.ts(48,16): error TS2589: Type instantiation is excessively deep and possibly infinite. -==== tests/cases/compiler/infiniteConstraints.ts (5 errors) ==== +==== tests/cases/compiler/infiniteConstraints.ts (7 errors) ==== // Both of the following types trigger the recursion limiter in getImmediateBaseConstraint type T1], { val: string }>["val"] }> = B; @@ -29,6 +31,10 @@ tests/cases/compiler/infiniteConstraints.ts(48,16): error TS2589: Type instantia declare function ensureNoDuplicates< T extends { [K in keyof T]: Extract["val"] extends Extract], Value>["val"] + ~~~~~ +!!! error TS2801: Proper Polymorphism type parameter U could not accept Generic type Value + ~~~~~ +!!! error TS2801: Proper Polymorphism type parameter U could not accept Generic type Value ? never : any } diff --git a/tests/baselines/reference/missingTypeArguments1.errors.txt b/tests/baselines/reference/missingTypeArguments1.errors.txt index c0e0f3e18bbb4..6ad484f3178f3 100644 --- a/tests/baselines/reference/missingTypeArguments1.errors.txt +++ b/tests/baselines/reference/missingTypeArguments1.errors.txt @@ -2,15 +2,17 @@ tests/cases/compiler/missingTypeArguments1.ts(4,15): error TS2314: Generic type tests/cases/compiler/missingTypeArguments1.ts(9,26): error TS2314: Generic type 'X2' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(14,9): error TS2314: Generic type 'X3' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(19,11): error TS2314: Generic type 'X4' requires 1 type argument(s). +tests/cases/compiler/missingTypeArguments1.ts(19,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type X4 tests/cases/compiler/missingTypeArguments1.ts(24,9): error TS2314: Generic type 'X5' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(29,15): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(34,26): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(39,9): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments1.ts(44,11): error TS2314: Generic type 'Y' requires 1 type argument(s). +tests/cases/compiler/missingTypeArguments1.ts(44,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y tests/cases/compiler/missingTypeArguments1.ts(49,9): error TS2314: Generic type 'Y' requires 1 type argument(s). -==== tests/cases/compiler/missingTypeArguments1.ts (10 errors) ==== +==== tests/cases/compiler/missingTypeArguments1.ts (12 errors) ==== interface I { } class Y {} class X { @@ -38,6 +40,8 @@ tests/cases/compiler/missingTypeArguments1.ts(49,9): error TS2314: Generic type p4: I ~~ !!! error TS2314: Generic type 'X4' requires 1 type argument(s). + ~~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type X4 } var a4: X4; @@ -73,6 +77,8 @@ tests/cases/compiler/missingTypeArguments1.ts(49,9): error TS2314: Generic type p9: I ~ !!! error TS2314: Generic type 'Y' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y } var a9: X9; diff --git a/tests/baselines/reference/missingTypeArguments2.errors.txt b/tests/baselines/reference/missingTypeArguments2.errors.txt index 0b51f40c1ed8f..fcd981b5234e7 100644 --- a/tests/baselines/reference/missingTypeArguments2.errors.txt +++ b/tests/baselines/reference/missingTypeArguments2.errors.txt @@ -1,10 +1,11 @@ tests/cases/compiler/missingTypeArguments2.ts(3,14): error TS2314: Generic type 'A' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments2.ts(4,5): error TS2314: Generic type 'A' requires 1 type argument(s). tests/cases/compiler/missingTypeArguments2.ts(5,10): error TS2314: Generic type 'A' requires 1 type argument(s). +tests/cases/compiler/missingTypeArguments2.ts(5,10): error TS2801: Proper Polymorphism type parameter T could not accept Generic type A tests/cases/compiler/missingTypeArguments2.ts(6,5): error TS2314: Generic type 'A' requires 1 type argument(s). -==== tests/cases/compiler/missingTypeArguments2.ts (4 errors) ==== +==== tests/cases/compiler/missingTypeArguments2.ts (5 errors) ==== class A { } var x: () => A; @@ -16,6 +17,8 @@ tests/cases/compiler/missingTypeArguments2.ts(6,5): error TS2314: Generic type ' var y: A; ~ !!! error TS2314: Generic type 'A' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type A (): A => null; ~ !!! error TS2314: Generic type 'A' requires 1 type argument(s). \ No newline at end of file diff --git a/tests/baselines/reference/neverReturningFunctions1.errors.txt b/tests/baselines/reference/neverReturningFunctions1.errors.txt index de3c6a0c53b1c..d7549935d5852 100644 --- a/tests/baselines/reference/neverReturningFunctions1.errors.txt +++ b/tests/baselines/reference/neverReturningFunctions1.errors.txt @@ -21,9 +21,10 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(139,9): error TS tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(141,5): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(148,9): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS7027: Unreachable code detected. +tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(204,74): error TS2801: Proper Polymorphism type parameter T could not accept Generic type Component -==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (23 errors) ==== +==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (24 errors) ==== function fail(message?: string): never { throw new Error(message); } @@ -274,6 +275,8 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS ): ComponentConstructor; export type ComponentDefinition = T & Partial & ThisType; + ~~~~~~~~~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type Component const Component = registerComponent('test-component', { schema: { diff --git a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt index c72f99027abfb..94adbf01abf76 100644 --- a/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt +++ b/tests/baselines/reference/recursiveResolveTypeMembers.errors.txt @@ -1,19 +1,25 @@ -tests/cases/compiler/recursiveResolveTypeMembers.ts(4,49): error TS2577: Return type annotation circularly references itself. +tests/cases/compiler/recursiveResolveTypeMembers.ts(3,6): error TS2456: Type alias 'PromisedTuple' circularly references itself. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,58): error TS2304: Cannot find name 'H'. +tests/cases/compiler/recursiveResolveTypeMembers.ts(4,65): error TS2315: Type 'PromisedTuple' is not generic. tests/cases/compiler/recursiveResolveTypeMembers.ts(4,79): error TS2304: Cannot find name 'R'. +tests/cases/compiler/recursiveResolveTypeMembers.ts(6,17): error TS2315: Type 'PromisedTuple' is not generic. -==== tests/cases/compiler/recursiveResolveTypeMembers.ts (3 errors) ==== +==== tests/cases/compiler/recursiveResolveTypeMembers.ts (5 errors) ==== // Repro from #25291 type PromisedTuple void> = + ~~~~~~~~~~~~~ +!!! error TS2456: Type alias 'PromisedTuple' circularly references itself. U extends (h: infer H, ...args: infer R) => [Promise, ...PromisedTuple] ? [] : [] - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2577: Return type annotation circularly references itself. ~ !!! error TS2304: Cannot find name 'H'. + ~~~~~~~~~~~~~~~~ +!!! error TS2315: Type 'PromisedTuple' is not generic. ~ !!! error TS2304: Cannot find name 'R'. type Promised = PromisedTuple<[1, 2, 3]> + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2315: Type 'PromisedTuple' is not generic. \ No newline at end of file diff --git a/tests/baselines/reference/recursiveResolveTypeMembers.types b/tests/baselines/reference/recursiveResolveTypeMembers.types index 6e7476e5e9e61..cd6a05f2f7678 100644 --- a/tests/baselines/reference/recursiveResolveTypeMembers.types +++ b/tests/baselines/reference/recursiveResolveTypeMembers.types @@ -2,7 +2,7 @@ // Repro from #25291 type PromisedTuple void> = ->PromisedTuple : PromisedTuple +>PromisedTuple : any >args : L U extends (h: infer H, ...args: infer R) => [Promise, ...PromisedTuple] ? [] : [] @@ -10,5 +10,5 @@ type PromisedTuple void> = >args : R type Promised = PromisedTuple<[1, 2, 3]> ->Promised : [] +>Promised : any diff --git a/tests/baselines/reference/returnTypeTypeArguments.errors.txt b/tests/baselines/reference/returnTypeTypeArguments.errors.txt index 080da44e7f706..2b1eca9ee430d 100644 --- a/tests/baselines/reference/returnTypeTypeArguments.errors.txt +++ b/tests/baselines/reference/returnTypeTypeArguments.errors.txt @@ -19,25 +19,29 @@ tests/cases/compiler/returnTypeTypeArguments.ts(52,15): error TS2314: Generic ty tests/cases/compiler/returnTypeTypeArguments.ts(53,26): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(54,9): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(55,11): error TS2314: Generic type 'X' requires 1 type argument(s). +tests/cases/compiler/returnTypeTypeArguments.ts(55,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type X tests/cases/compiler/returnTypeTypeArguments.ts(56,9): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(57,15): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(58,26): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(59,9): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(60,11): error TS2314: Generic type 'Y' requires 1 type argument(s). +tests/cases/compiler/returnTypeTypeArguments.ts(60,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y tests/cases/compiler/returnTypeTypeArguments.ts(61,9): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(65,15): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(66,26): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(67,9): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(68,11): error TS2314: Generic type 'X' requires 1 type argument(s). +tests/cases/compiler/returnTypeTypeArguments.ts(68,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type X tests/cases/compiler/returnTypeTypeArguments.ts(69,9): error TS2314: Generic type 'X' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(70,15): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(71,26): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(72,9): error TS2314: Generic type 'Y' requires 1 type argument(s). tests/cases/compiler/returnTypeTypeArguments.ts(73,11): error TS2314: Generic type 'Y' requires 1 type argument(s). +tests/cases/compiler/returnTypeTypeArguments.ts(73,11): error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y tests/cases/compiler/returnTypeTypeArguments.ts(74,9): error TS2314: Generic type 'Y' requires 1 type argument(s). -==== tests/cases/compiler/returnTypeTypeArguments.ts (37 errors) ==== +==== tests/cases/compiler/returnTypeTypeArguments.ts (41 errors) ==== class One{ value: T; } @@ -135,6 +139,8 @@ tests/cases/compiler/returnTypeTypeArguments.ts(74,9): error TS2314: Generic typ p4: I ~ !!! error TS2314: Generic type 'X' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type X p5: X ~ !!! error TS2314: Generic type 'X' requires 1 type argument(s). @@ -150,6 +156,8 @@ tests/cases/compiler/returnTypeTypeArguments.ts(74,9): error TS2314: Generic typ p9: I ~ !!! error TS2314: Generic type 'Y' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y pa: Y ~ !!! error TS2314: Generic type 'Y' requires 1 type argument(s). @@ -168,6 +176,8 @@ tests/cases/compiler/returnTypeTypeArguments.ts(74,9): error TS2314: Generic typ p4: I ~ !!! error TS2314: Generic type 'X' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type X p5: X ~ !!! error TS2314: Generic type 'X' requires 1 type argument(s). @@ -183,6 +193,8 @@ tests/cases/compiler/returnTypeTypeArguments.ts(74,9): error TS2314: Generic typ p9: I ~ !!! error TS2314: Generic type 'Y' requires 1 type argument(s). + ~ +!!! error TS2801: Proper Polymorphism type parameter T could not accept Generic type Y pa: Y ~ !!! error TS2314: Generic type 'Y' requires 1 type argument(s). diff --git a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias1.ts b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias1.ts index b3ca601b6dbd5..79d1c736df30d 100644 --- a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias1.ts +++ b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias1.ts @@ -1,9 +1,9 @@ /// -////type List1 = T[]; ////type List4 = /*2*/T[]; ////type List3 = /*3*/; +//// type List1 - -////type Map1 = []; -////type Map1 = /*2*/[]; -////type Map1 = > { +// foo1(): Container; +// foo2(): Container; +// map1(f: (a: A) => B): (something: A) => B; +// } + +// function fff(foo: Itertable) { +// var q = foo.foo1(); +// var w = foo.foo2(); +// foo.map1 +// } + +// interface CommonGeric { +// func(): Set; +// } + +// var q: CommonGeric; +// var w = q.func(); + +// interface Monad> { +// map1(f: (a: A) => B): (something: A) => B; + +// map(f: (a: A) => B): (something: T) => T; + +// lift(a: A): T; +// // join(tta: T>): T; +// } + +// type sn = (tmp: string) => number + +// function MONAD(m: Monad,f:sn) { +// // var w = m.map1(f); +// var w2 = m.map(f); +// // var q = m.lift(1); +// } + +// 2800 "Type Constructor Polymorphism type parameter {0} could not accept proper type {1}" +// 2801 "Proper Constructor Polymorphism type parameter {0} could not accept Generic type {1} " +// 2802 "Type Constructor Polymorphism type parameter {0} could not have constraint" + +// NOTE: 2801 is a strict error which limits a lot of things, +// like `type Q> = Partial` + +// NOTE: 2802 is not need, but I do not know how to handle constraint for type constructor polymorphism. You can see my example in the PR to help. + +// test1 +interface Generic{} +interface TypeConstructor>{} + +const foo1: TypeConstructor // error: Type Constructor Polymorphism type parameter {0} could not accept proper type {1} +const foo2: TypeConstructor // no error +const foo3: TypeConstructor> // error: Generic type 'Generic' requires 1 type argument(s). +const foo4: TypeConstructor // +const foo5: TypeConstructor> // error: +const foo6: Generic // +const foo7: Generic // +const foo8: Generic> // +const foo9: Generic // +const foo9: Generic> //