From ad7b7e9236f935db635234bbbfc70c103a4dffd2 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Mon, 31 Aug 2020 18:14:39 +0800 Subject: [PATCH 01/37] beta version. --- src/compiler/checker.ts | 12 ++++++------ src/compiler/factory/nodeFactory.ts | 3 ++- src/compiler/parser.ts | 7 ++++++- src/compiler/types.ts | 5 ++++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 441e75ded3199..942cb3b2a40db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30241,12 +30241,12 @@ namespace ts { return quickType; } // If a type has been cached for the node, return it. - if (node.flags & NodeFlags.TypeCached && flowTypeCache) { - const cachedType = flowTypeCache[getNodeId(node)]; - if (cachedType) { - return cachedType; - } - } + // if (node.flags & NodeFlags.TypeCached && flowTypeCache) { + // const cachedType = flowTypeCache[getNodeId(node)]; + // if (cachedType) { + // return cachedType; + // } + // } const startInvocationCount = flowInvocationCount; const type = checkExpression(node); // If control flow analysis was required to determine the type, it is worth caching. diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index a9679f453fe43..d16756c6e7a51 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1074,7 +1074,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, @@ -1084,6 +1084,7 @@ namespace ts { node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; + node.tParams = tParams; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ebcd9ce14994e..a8349044e0681 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2824,6 +2824,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 @@ -2845,7 +2850,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 50b9e5d78aeee..569f2438d3e5b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1191,6 +1191,9 @@ namespace ts { // For error recovery purposes. expression?: Expression; + + // If this is not empty, it is a type constructor. + tParams?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { @@ -6665,7 +6668,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; From b97c40a11adebeffcfb3062ef2320527df7ce0c9 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 1 Sep 2020 19:05:39 +0800 Subject: [PATCH 02/37] analytcs something. --- dev.md | 22 ++++++++++++++++++++++ tmp.ts | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 dev.md create mode 100644 tmp.ts diff --git a/dev.md b/dev.md new file mode 100644 index 0000000000000..711fa4078a7b9 --- /dev/null +++ b/dev.md @@ -0,0 +1,22 @@ +How to add HKT + +getTypeFromTypeNode + - what is TypeNode, like ` Set` in `var q: Set` + 1. function getTypeFromTypeReference(node: TypeReferenceType): Type + - what is TypeReferenceType, it is TypeNode, with something more. + 1. get symbol of the TypeReferenceType + 1. function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { + 1. function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType { <-- this function use GenericType! + 2. createDeferredTypeReference <-- this function give concentrate type to generic type! + +TypeArguments means the concentrate type like number, boolean +TypeParameters means the abstract Generic Symbol like T, U + +1. get TypeReferenceType(it is a node in fact) of one variable node +2. get the symbol of the TypeReferenceType +3. get declration type according to the symbol +4. get typeArguments(type) -- this step is not that easy +5. add cache to declration of typeArguments. + + +instantiateType <-------- seems this do the final map work. \ No newline at end of file diff --git a/tmp.ts b/tmp.ts new file mode 100644 index 0000000000000..eb2a81b7174b4 --- /dev/null +++ b/tmp.ts @@ -0,0 +1,20 @@ +interface Type{ + +} + +interface TypeConstructor extends Type{ + parameters: Type[] +} + +interface TypeArgument extends Type{ + +} + +function createInstanceTypeWithTypeConstructor(tc: TypeConstructor, tas: TypeArgument[]) { + if(tc.parameters.length !== tas.length){ + throw new Error(`too much or too little parameter for hkt {tc}`); + } + + + +} \ No newline at end of file From bc66c970d572a3d8d2a02dd01b295cb538fb3bc9 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 1 Sep 2020 17:23:00 +0800 Subject: [PATCH 03/37] first step! --- dev.md | 4 ++++ src/compiler/checker.ts | 28 ++++++++++++++++++++++++++-- src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/types.ts | 9 +++++++-- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/dev.md b/dev.md index 711fa4078a7b9..7d8b164b6d7fb 100644 --- a/dev.md +++ b/dev.md @@ -1,5 +1,9 @@ How to add HKT +This implement is a toy, it is not parsed as BNF. I only promise the type constructor could check for the correct parameter numbers. + + + getTypeFromTypeNode - what is TypeNode, like ` Set` in `var q: Set` 1. function getTypeFromTypeReference(node: TypeReferenceType): Type diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 942cb3b2a40db..6da6baa01c1f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9384,7 +9384,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.tParamDeclarations && declration.tParamDeclarations.length > 0) { + tmp.flags |= TypeFlags.TypeConstructor; + // This line is important, which combines Node and Type. + // for now Node.paras is not used but its length. + tmp.tParams = declration.tParamDeclarations.length; + } + links.declaredType = tmp; + } + return links.declaredType; } function getDeclaredTypeOfAlias(symbol: Symbol): Type { @@ -12140,7 +12154,13 @@ 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; + if (isTypeConstructorTypeParameter(res)) { + return getRegularTypeOfLiteralType(res); + } + if (checkNoTypeArguments(node, symbol)) { + return getRegularTypeOfLiteralType(res); + } + return errorType; } if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { const jsdocType = getTypeFromJSDocValueReference(node, symbol); @@ -13619,6 +13639,10 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } + function isTypeConstructorTypeParameter(type: Type): boolean { + return !!(type.flags & TypeFlags.TypeParameter && !!(type).tParams); + } + function getSimplifiedType(type: Type, writing: boolean): Type { return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type, writing) : type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type, writing) : diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index d16756c6e7a51..3793918b5748d 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1084,7 +1084,7 @@ namespace ts { node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; - node.tParams = tParams; + node.tParamDeclarations = tParams; return node; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 569f2438d3e5b..cc83c478832d1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1082,7 +1082,7 @@ namespace ts { /*@internal*/ readonly autoGenerateFlags?: GeneratedIdentifierFlags; // Specifies whether to auto-generate the text for an identifier. /*@internal*/ readonly autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. /*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. } @@ -1193,7 +1193,7 @@ namespace ts { expression?: Expression; // If this is not empty, it is a type constructor. - tParams?: NodeArray; + tParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { @@ -4832,6 +4832,7 @@ namespace ts { Null = 1 << 16, Never = 1 << 17, // Never type TypeParameter = 1 << 18, // Type parameter + TypeConstructor = 1<< 27, // Type Constructor, this is an additional flag of TypeParameter. Object = 1 << 19, // Object type Union = 1 << 20, // Union (T | U) Intersection = 1 << 21, // Intersection (T & U) @@ -5269,6 +5270,10 @@ namespace ts { isThisType?: boolean; /* @internal */ resolvedDefaultType?: Type; + + // would it be used? or we just need the number of parameters? + /* @internal */ + tParams?: number; // Or it should be TypeParameter[]? In parser I parse the node use a BNF in scala paper. } // Indexed access types (TypeFlags.IndexedAccess) From 5df339436f3450b59cbc23b092162f192065acc7 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 2 Sep 2020 18:49:38 +0800 Subject: [PATCH 04/37] continue analytics. --- dev.md | 28 +++++++++++++++++++++++++--- src/compiler/types.ts | 2 +- tmp.ts | 24 ++++++++++++++++++++---- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/dev.md b/dev.md index 7d8b164b6d7fb..d0e5bc4258083 100644 --- a/dev.md +++ b/dev.md @@ -2,6 +2,8 @@ How to add HKT This implement is a toy, it is not parsed as BNF. I only promise the type constructor could check for the correct parameter numbers. +1. AST: add possiable parameters to TypeParameter when parsing +2. convert AST to proper Type getTypeFromTypeNode @@ -16,11 +18,31 @@ getTypeFromTypeNode TypeArguments means the concentrate type like number, boolean TypeParameters means the abstract Generic Symbol like T, U + +instantiateType <-------- seems this do the final map work. + + +Q: How does Generic works for now? +A: 1. get TypeReferenceType(it is a node in fact) of one variable node 2. get the symbol of the TypeReferenceType 3. get declration type according to the symbol -4. get typeArguments(type) -- this step is not that easy -5. add cache to declration of typeArguments. +4. get typeArguments(type) with default parameter and given typeParameters -- this step is not that easy +5. add cache to the type of the generic symbol. + +1. get the type of the symbol. + + +Here are some important function signature: + +// craete resolvedTypeArguments +function getTypeArguments(type: TypeReference): readonly Type[] +function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType + - If the symbolLink of this symbol does not have `declaredType`, it would create a `ObjectType` whose `target` is itself, and set it as declaredType. +// +function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type -instantiateType <-------- seems this do the final map work. \ No newline at end of file +// +function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference + - this function would try get cached value(key is calculated through typeArguments' ids) from `target.instantiations`, if not create and cache a `TypeReference` type, set its property `resolvedTypeArguments` as `typeArguments` and property `target` as `target`(from function parameters). diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cc83c478832d1..96e27c75c8991 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1082,7 +1082,7 @@ namespace ts { /*@internal*/ readonly autoGenerateFlags?: GeneratedIdentifierFlags; // Specifies whether to auto-generate the text for an identifier. /*@internal*/ readonly autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. /*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. } diff --git a/tmp.ts b/tmp.ts index eb2a81b7174b4..4f5ec82d9113f 100644 --- a/tmp.ts +++ b/tmp.ts @@ -1,3 +1,22 @@ +interface Itertable> { + filter(p: (x: T) => boolean): Container; +} +var w: Itertable; +w.filter; + + +interface Gener { + aaafff(): Set; + qqqSSS(): T; +} + +var q: Gener; +q.aaafff; +q.qqqSSS; + + + + interface Type{ } @@ -14,7 +33,4 @@ function createInstanceTypeWithTypeConstructor(tc: TypeConstructor, tas: TypeArg if(tc.parameters.length !== tas.length){ throw new Error(`too much or too little parameter for hkt {tc}`); } - - - -} \ No newline at end of file +} From 76d4940a5582d05194360c95f09b020a015ee1c8 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 3 Sep 2020 01:55:57 +0800 Subject: [PATCH 05/37] third step! --- dev.md | 8 ++++++++ src/compiler/checker.ts | 43 +++++++++++++++++++++++++---------------- src/compiler/types.ts | 2 ++ 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/dev.md b/dev.md index d0e5bc4258083..d50e48f99f11f 100644 --- a/dev.md +++ b/dev.md @@ -5,6 +5,10 @@ This implement is a toy, it is not parsed as BNF. I only promise the type constr 1. AST: add possiable parameters to TypeParameter when parsing 2. convert AST to proper Type +- add more check for arguments + - allow generic as typeArguments // seems this is done already + - check typeArguments and typeParameter whether match, especially paramters + - getTypeFromTypeNode - what is TypeNode, like ` Set` in `var q: Set` @@ -46,3 +50,7 @@ function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbo // function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference - this function would try get cached value(key is calculated through typeArguments' ids) from `target.instantiations`, if not create and cache a `TypeReference` type, set its property `resolvedTypeArguments` as `typeArguments` and property `target` as `target`(from function parameters). + +## Need final decision from Core Team +1. TypeArguments need a flag or boolean to mark itself. For a generic type could be valid typeargument for now, we should not check whether it has typearguments for now. +So, where to add the flag, which type should have this flag. \ No newline at end of file diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6da6baa01c1f3..a2e3518957f2a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12048,25 +12048,28 @@ 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; + if (isTypeReferenceNode(node) && node.isTypeArguments) { } + 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 @@ -12141,6 +12144,7 @@ namespace ts { } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { + Debug.assert(isTypeReferenceNode(node)); if (symbol === unknownSymbol) { return errorType; } @@ -12338,6 +12342,11 @@ namespace ts { } function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] | undefined { + forEach(node.typeArguments, (t) => { + if (isTypeReferenceNode(t)) { + t.isTypeArguments = true; + } + }); return map(node.typeArguments, getTypeFromTypeNode); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 96e27c75c8991..b25ce908e1455 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1523,6 +1523,8 @@ namespace ts { export interface TypeReferenceNode extends NodeWithTypeArguments { readonly kind: SyntaxKind.TypeReference; readonly typeName: EntityName; + //@internal + isTypeArguments: boolean; } export interface TypePredicateNode extends TypeNode { From 673241623c595afb2de6d2210ed44d3d26dcc073 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 3 Sep 2020 16:19:57 +0800 Subject: [PATCH 06/37] come to mapper. --- src/compiler/checker.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a2e3518957f2a..446c0ab6d15e4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14996,6 +14996,16 @@ namespace ts { function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { const flags = type.flags; + if(flags & TypeFlags.TypeConstructor){ + // this is a demo implement, and not well considered. + const concentrateGenericType = getMappedType(type, mapper); + // or maybe we could get the symbol, then get value declration. But it seems target is a quick way. + const tmp = (concentrateGenericType).target; // this should be an obejct TypeFlag. + Debug.assert(!!tmp,"unhandled condition for typeconstructor."); + const resolvedTypeArguments = (tmp).resolvedTypeArguments; + const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); + return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference(tmp, newTypeArguments) : concentrateGenericType; + } if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); } From 4450ac679c43ee136d729e1bccbba51105d0e089 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 3 Sep 2020 18:46:04 +0800 Subject: [PATCH 07/37] just update some comment. --- src/compiler/checker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a2e3518957f2a..44b56a20ec4f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12158,6 +12158,12 @@ namespace ts { // Get type from reference to named type that cannot be generic (enum or type parameter) const res = tryGetDeclaredTypeOfSymbol(symbol); if (res) { + /* + interface Itertable> { + filter(p: (x: T) => boolean): Container; + ^ this should not report as error. + } + */ if (isTypeConstructorTypeParameter(res)) { return getRegularTypeOfLiteralType(res); } @@ -14617,7 +14623,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; } From c67a88a46e177b8908160c328d56783343425e53 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Fri, 4 Sep 2020 10:16:47 +0800 Subject: [PATCH 08/37] add comment. --- dev.md | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/dev.md b/dev.md index d50e48f99f11f..d2563e7bb6108 100644 --- a/dev.md +++ b/dev.md @@ -5,11 +5,6 @@ This implement is a toy, it is not parsed as BNF. I only promise the type constr 1. AST: add possiable parameters to TypeParameter when parsing 2. convert AST to proper Type -- add more check for arguments - - allow generic as typeArguments // seems this is done already - - check typeArguments and typeParameter whether match, especially paramters - - - getTypeFromTypeNode - what is TypeNode, like ` Set` in `var q: Set` 1. function getTypeFromTypeReference(node: TypeReferenceType): Type @@ -51,6 +46,38 @@ function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbo function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference - this function would try get cached value(key is calculated through typeArguments' ids) from `target.instantiations`, if not create and cache a `TypeReference` type, set its property `resolvedTypeArguments` as `typeArguments` and property `target` as `target`(from function parameters). +// most important function, before this step, the mapper has been set but not used. and the symbol has a flag mark it as initilized. +function getTypeOfSymbol(symbol: Symbol): Type +function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) + ## Need final decision from Core Team 1. TypeArguments need a flag or boolean to mark itself. For a generic type could be valid typeargument for now, we should not check whether it has typearguments for now. -So, where to add the flag, which type should have this flag. \ No newline at end of file +So, where to add the flag, which type should have this flag. + +## Need improvement +1. high light the same symbol for TypeConstructor in the interface. +2. the TypeConstructor in the TypeParameter declration need quickinfo. +3. add more check for arguments + - allow generic as typeArguments // seems this is done already + - check typeArguments and typeParameter whether match, especially paramters + +## Key Point +1. distinguish whether the typereference is a typeconstructor or not. + + + + + + + + + + + +``` ts +var w: Itertable; +``` +call getTypeFromTypeReference on `TypeReference(node) Set` + in the call + 1. get the symbol of `Set` + 2. call getTypeReferenceType(node, symbol) to get the returned . From 2bb3a1556bc7d1d8b8e9ecea3b456629205f0234 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Mon, 7 Sep 2020 19:22:57 +0800 Subject: [PATCH 09/37] work for simple conditon. --- src/compiler/checker.ts | 14 ++++++----- src/compiler/types.ts | 2 ++ tmp.ts | 52 ++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 83ac9aaa32840..9c393fe2a09e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12165,6 +12165,10 @@ namespace ts { } */ if (isTypeConstructorTypeParameter(res)) { + if(node.typeArguments?.length !== res.tParams){ + //check whether type arguments match type parameters. + } + res.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); return getRegularTypeOfLiteralType(res); } if (checkNoTypeArguments(node, symbol)) { @@ -13654,7 +13658,7 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } - function isTypeConstructorTypeParameter(type: Type): boolean { + function isTypeConstructorTypeParameter(type: Type): type is TypeParameter { return !!(type.flags & TypeFlags.TypeParameter && !!(type).tParams); } @@ -14787,7 +14791,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 => instantiateTypeWorker(t, combinedMapper)); //maybe this is instantiateType? Or another function? I just want to handle typeConstructor situation. const id = getTypeListId(typeArguments); let result = links.instantiations!.get(id); if (!result) { @@ -15006,11 +15010,9 @@ namespace ts { // this is a demo implement, and not well considered. const concentrateGenericType = getMappedType(type, mapper); // or maybe we could get the symbol, then get value declration. But it seems target is a quick way. - const tmp = (concentrateGenericType).target; // this should be an obejct TypeFlag. - Debug.assert(!!tmp,"unhandled condition for typeconstructor."); - const resolvedTypeArguments = (tmp).resolvedTypeArguments; + const resolvedTypeArguments = (type).resolvedTypeConstructorParam; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference(tmp, newTypeArguments) : concentrateGenericType; + return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments) : concentrateGenericType; } if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b25ce908e1455..8a74d90a2f136 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5276,6 +5276,8 @@ namespace ts { // would it be used? or we just need the number of parameters? /* @internal */ tParams?: number; // Or it should be TypeParameter[]? In parser I parse the node use a BNF in scala paper. + /* @internal */ + resolvedTypeConstructorParam?: Type[]; } // Indexed access types (TypeFlags.IndexedAccess) diff --git a/tmp.ts b/tmp.ts index 4f5ec82d9113f..9ab5c8c3593b9 100644 --- a/tmp.ts +++ b/tmp.ts @@ -1,36 +1,36 @@ -interface Itertable> { - filter(p: (x: T) => boolean): Container; -} -var w: Itertable; -w.filter; - - -interface Gener { - aaafff(): Set; - qqqSSS(): T; -} +// interface Itertable> { +// foo1(): Container; +// foo2(): Container; +// map1(f: (a: A) => B): (something: A) => B; +// } -var q: Gener; -q.aaafff; -q.qqqSSS; +// 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; -interface Type{ + map(f: (a: A) => B): (something: T) => T; + lift(a: A): T; + // join(tta: T>): T; } -interface TypeConstructor extends Type{ - parameters: Type[] -} - -interface TypeArgument extends Type{ - -} +type sn = (tmp: string) => number -function createInstanceTypeWithTypeConstructor(tc: TypeConstructor, tas: TypeArgument[]) { - if(tc.parameters.length !== tas.length){ - throw new Error(`too much or too little parameter for hkt {tc}`); - } +function MONAD(m: Monad,f:sn) { + // var w = m.map1(f); + var w2 = m.map(f); + // var q = m.lift(1); } + \ No newline at end of file From 57b5acbe1ec1fcc722f381a216d3c74b8dda03a5 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 8 Sep 2020 19:16:03 +0800 Subject: [PATCH 10/37] finally, I know the reason. --- src/compiler/checker.ts | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c393fe2a09e6..c179f5f9bd2bf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14791,7 +14791,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 => instantiateTypeWorker(t, combinedMapper)); //maybe this is instantiateType? Or another function? I just want to handle typeConstructor situation. + 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) { @@ -14808,7 +14808,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); } @@ -15004,19 +15004,30 @@ namespace ts { return result; } - function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { + // this function is mainly for the change in function `getObjectTypeInstantiation`, another choice is written in the comment of that changed line. + function instantiateTypeOfTypeParameter(type: Type, mapper: TypeMapper): Type { const flags = type.flags; - if(flags & TypeFlags.TypeConstructor){ + if (flags & TypeFlags.TypeConstructor) { // this is a demo implement, and not well considered. - const concentrateGenericType = getMappedType(type, mapper); - // or maybe we could get the symbol, then get value declration. But it seems target is a quick way. + const concentrateGenericType = getMappedType(type, mapper); + if(concentrateGenericType === type){ + debugger;//on which condition this would happen? + return type; + } const resolvedTypeArguments = (type).resolvedTypeConstructorParam; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments) : concentrateGenericType; + return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); } - if (flags & TypeFlags.TypeParameter) { + else { return getMappedType(type, mapper); } + } + + function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { + const flags = type.flags; + if (flags & TypeFlags.TypeParameter) { + return instantiateTypeOfTypeParameter(type, mapper); + } if (flags & TypeFlags.Object) { const objectFlags = (type).objectFlags; if (objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous | ObjectFlags.Mapped)) { From 43041c2c433b0b018918920fa15df20d0607bf6e Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 9 Sep 2020 12:08:50 +0800 Subject: [PATCH 11/37] works for nested typeconstructor. --- dev.md | 27 +++++++++++---------------- src/compiler/checker.ts | 27 ++++++++++++++++++++++----- src/compiler/types.ts | 3 +++ tmp.ts | 1 - 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/dev.md b/dev.md index d2563e7bb6108..d794892422d61 100644 --- a/dev.md +++ b/dev.md @@ -18,9 +18,6 @@ TypeArguments means the concentrate type like number, boolean TypeParameters means the abstract Generic Symbol like T, U -instantiateType <-------- seems this do the final map work. - - Q: How does Generic works for now? A: 1. get TypeReferenceType(it is a node in fact) of one variable node @@ -30,8 +27,6 @@ A: 5. add cache to the type of the generic symbol. 1. get the type of the symbol. - - Here are some important function signature: // craete resolvedTypeArguments @@ -54,29 +49,29 @@ function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, 1. TypeArguments need a flag or boolean to mark itself. For a generic type could be valid typeargument for now, we should not check whether it has typearguments for now. So, where to add the flag, which type should have this flag. +2. nested typeconstructor map. This does not exist in only generic world, but now we could have `Container>`. If we store typearguments into the type of the symbol of typeconstructor `Container`, it would be a infinite loop. +I create a tmp type which have flag "TypeConstructorWrapper" for the node, rather than the symbol. + ## Need improvement + 1. high light the same symbol for TypeConstructor in the interface. -2. the TypeConstructor in the TypeParameter declration need quickinfo. -3. add more check for arguments +2. add more check for arguments - allow generic as typeArguments // seems this is done already - check typeArguments and typeParameter whether match, especially paramters +3. the TypeConstructor in the TypeParameter declration need quickinfo. +4. the methods in interface need quick info. +?auto infer typeArgument ## Key Point -1. distinguish whether the typereference is a typeconstructor or not. - - - - - - - - +1. distinguish whether the typereference is a typeconstructor or not. +2. nested typeconstructor. ``` ts var w: Itertable; ``` + call getTypeFromTypeReference on `TypeReference(node) Set` in the call 1. get the symbol of `Set` diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c179f5f9bd2bf..78d2401c66e1d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12168,8 +12168,13 @@ namespace ts { if(node.typeArguments?.length !== res.tParams){ //check whether type arguments match type parameters. } - res.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); - return getRegularTypeOfLiteralType(res); + // res.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); + // return res; + const tmp = createTypeParameter(symbol); + tmp.flags |= TypeFlags.TypeConstructorWrapper; + tmp.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); + tmp.origionalTypeParameter = res; + return tmp; } if (checkNoTypeArguments(node, symbol)) { return getRegularTypeOfLiteralType(res); @@ -15005,16 +15010,28 @@ namespace ts { } // this function is mainly for the change in function `getObjectTypeInstantiation`, another choice is written in the comment of that changed line. - function instantiateTypeOfTypeParameter(type: Type, mapper: TypeMapper): Type { + function instantiateTypeOfTypeParameter(type: TypeParameter, mapper: TypeMapper): Type { const flags = type.flags; - if (flags & TypeFlags.TypeConstructor) { + if (flags & TypeFlags.TypeConstructorWrapper) { + debugger; + const origionalTypeConstructorParameter = type.origionalTypeParameter!; + 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); + return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); + } + else if (flags & TypeFlags.TypeConstructor) { // this is a demo implement, and not well considered. const concentrateGenericType = getMappedType(type, mapper); if(concentrateGenericType === type){ debugger;//on which condition this would happen? return type; } - const resolvedTypeArguments = (type).resolvedTypeConstructorParam; + const resolvedTypeArguments = (type).resolvedTypeConstructorParam; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8a74d90a2f136..c7ccba506e6b9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4835,6 +4835,7 @@ namespace ts { Never = 1 << 17, // Never type TypeParameter = 1 << 18, // Type parameter TypeConstructor = 1<< 27, // Type Constructor, this is an additional flag of TypeParameter. + TypeConstructorWrapper = 1<< 28, // Type Constructor, this is an additional flag of TypeParameter. Object = 1 << 19, // Object type Union = 1 << 20, // Union (T | U) Intersection = 1 << 21, // Intersection (T & U) @@ -5278,6 +5279,8 @@ namespace ts { tParams?: number; // Or it should be TypeParameter[]? In parser I parse the node use a BNF in scala paper. /* @internal */ resolvedTypeConstructorParam?: Type[]; + /* @internal */ + origionalTypeParameter?: TypeParameter; } // Indexed access types (TypeFlags.IndexedAccess) diff --git a/tmp.ts b/tmp.ts index 9ab5c8c3593b9..d849221577132 100644 --- a/tmp.ts +++ b/tmp.ts @@ -33,4 +33,3 @@ function MONAD(m: Monad,f:sn) { var w2 = m.map(f); // var q = m.lift(1); } - \ No newline at end of file From 1109ab6464fb49f5e4b382110f29c1204d75bcb1 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 9 Sep 2020 23:32:01 +0800 Subject: [PATCH 12/37] fix quickinfo. --- src/compiler/checker.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78d2401c66e1d..4c02d0929561f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15026,14 +15026,7 @@ namespace ts { } else if (flags & TypeFlags.TypeConstructor) { // this is a demo implement, and not well considered. - const concentrateGenericType = getMappedType(type, mapper); - if(concentrateGenericType === type){ - debugger;//on which condition this would happen? - return type; - } - const resolvedTypeArguments = (type).resolvedTypeConstructorParam; - const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); + return getMappedType(type, mapper); } else { return getMappedType(type, mapper); From 4356e7440f3886939ae7497cc5cfe007d717f173 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Mon, 14 Sep 2020 18:52:17 +0800 Subject: [PATCH 13/37] fix and more clear code. --- src/compiler/checker.ts | 50 ++++++++++++++++++++--------------------- src/compiler/parser.ts | 12 ++++++++-- src/compiler/types.ts | 18 ++++++++++----- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c02d0929561f..2da914d8206a6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9391,10 +9391,10 @@ namespace ts { const declration = symbol.declarations[index]; // this means it is typeConstructor. if (isTypeParameterDeclaration(declration) && declration.tParamDeclarations && declration.tParamDeclarations.length > 0) { - tmp.flags |= TypeFlags.TypeConstructor; + tmp.flags |= TypeFlags.TypeConstructorDeclaration; // This line is important, which combines Node and Type. - // for now Node.paras is not used but its length. - tmp.tParams = declration.tParamDeclarations.length; + // for now Node.paras is not used but its length. So constrait is not used for now. + (tmp).tParams = declration.tParamDeclarations.length; } links.declaredType = tmp; } @@ -12048,7 +12048,7 @@ namespace ts { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (isTypeReferenceNode(node) && node.isTypeArguments) { } + if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { } else { if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); @@ -12144,7 +12144,7 @@ namespace ts { } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { - Debug.assert(isTypeReferenceNode(node)); + // Debug.assert(isTypeReferenceNode(node)); if (symbol === unknownSymbol) { return errorType; } @@ -12164,16 +12164,16 @@ namespace ts { ^ this should not report as error. } */ - if (isTypeConstructorTypeParameter(res)) { + if (isTypeParameterTypeConstructorDeclaration(res)) { if(node.typeArguments?.length !== res.tParams){ //check whether type arguments match type parameters. } // res.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); // return res; const tmp = createTypeParameter(symbol); - tmp.flags |= TypeFlags.TypeConstructorWrapper; - tmp.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); - tmp.origionalTypeParameter = res; + tmp.flags |= TypeFlags.TypeConstructorInstance; + (tmp).resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); + (tmp).origionalTypeConstructorDeclaration = res; return tmp; } if (checkNoTypeArguments(node, symbol)) { @@ -12357,11 +12357,6 @@ namespace ts { } function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] | undefined { - forEach(node.typeArguments, (t) => { - if (isTypeReferenceNode(t)) { - t.isTypeArguments = true; - } - }); return map(node.typeArguments, getTypeFromTypeNode); } @@ -13663,8 +13658,12 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } - function isTypeConstructorTypeParameter(type: Type): type is TypeParameter { - return !!(type.flags & TypeFlags.TypeParameter && !!(type).tParams); + function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorDeclaration { + return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorDeclaration); + } + + function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorInstance { + return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorInstance); } function getSimplifiedType(type: Type, writing: boolean): Type { @@ -15012,9 +15011,9 @@ namespace ts { // 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 (flags & TypeFlags.TypeConstructorWrapper) { + if (isTypeParameterTypeConstructorInstance(type)) { debugger; - const origionalTypeConstructorParameter = type.origionalTypeParameter!; + const origionalTypeConstructorParameter = type.origionalTypeConstructorDeclaration!; const resolvedTypeConstructorParam = type.resolvedTypeConstructorParam; const concentrateGenericType = getMappedType(origionalTypeConstructorParameter, mapper); if (concentrateGenericType === origionalTypeConstructorParameter) { @@ -15024,8 +15023,9 @@ namespace ts { const newTypeArguments = instantiateTypes(resolvedTypeConstructorParam, mapper); return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); } - else if (flags & TypeFlags.TypeConstructor) { + 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 { @@ -30313,12 +30313,12 @@ namespace ts { return quickType; } // If a type has been cached for the node, return it. - // if (node.flags & NodeFlags.TypeCached && flowTypeCache) { - // const cachedType = flowTypeCache[getNodeId(node)]; - // if (cachedType) { - // return cachedType; - // } - // } + if (node.flags & NodeFlags.TypeCached && flowTypeCache) { + const cachedType = flowTypeCache[getNodeId(node)]; + if (cachedType) { + return cachedType; + } + } const startInvocationCount = flowInvocationCount; const type = checkExpression(node); // If control flow analysis was required to determine the type, it is worth caching. diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a8349044e0681..3809a653df3b5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2452,7 +2452,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 @@ -2460,7 +2468,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) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c7ccba506e6b9..a39e54ff4d8ad 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4834,8 +4834,10 @@ namespace ts { Null = 1 << 16, Never = 1 << 17, // Never type TypeParameter = 1 << 18, // Type parameter - TypeConstructor = 1<< 27, // Type Constructor, this is an additional flag of TypeParameter. - TypeConstructorWrapper = 1<< 28, // Type Constructor, this is an additional flag of TypeParameter. + // @internal + TypeConstructorDeclaration = 1<< 27, // Type Constructor Declaration, this is an additional flag of TypeParameter. This should include the constraint and parameter constrait. + // @internal + TypeConstructorInstance = 1<< 28, // 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) @@ -5273,14 +5275,20 @@ namespace ts { isThisType?: boolean; /* @internal */ resolvedDefaultType?: Type; + } - // would it be used? or we just need the number of parameters? + // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorDeclaration) + export interface TypeConstructorDeclaration extends TypeParameter{ /* @internal */ - tParams?: number; // Or it should be TypeParameter[]? In parser I parse the node use a BNF in scala paper. + tParams?: number; // Not allowed constraint for now, this might be a very complex feature. + } + + // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorInstance) + export interface TypeConstructorInstance extends TypeParameter{ /* @internal */ resolvedTypeConstructorParam?: Type[]; /* @internal */ - origionalTypeParameter?: TypeParameter; + origionalTypeConstructorDeclaration?: TypeConstructorDeclaration; } // Indexed access types (TypeFlags.IndexedAccess) From e6aab71510ccf0dc8eb713b64cbeb2b439e1bc01 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 15 Sep 2020 01:46:40 +0800 Subject: [PATCH 14/37] resolve most baseline. --- src/compiler/checker.ts | 23 ++++++++++++++++++- .../recursiveResolveTypeMembers.errors.txt | 14 +++++++---- .../recursiveResolveTypeMembers.types | 4 ++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2da914d8206a6..de468d1fcf926 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12048,7 +12048,28 @@ namespace ts { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { } + // type reference without typeArguments. Like Set, rather than Set + if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { + // These are not well considered, just for passing test cases. + + // get the type-constructor(the origional meaning) + const parentNode = (node.parent); // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) + const typeParameterIndex = parentNode.typeArguments!.findIndex(t => t === node); + if (typeParameterIndex >= 0) { + const meaning = SymbolFlags.Type; + const parentSymbol = resolveTypeReferenceName(getTypeReferenceName(parentNode), meaning); + const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); + if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { + const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; + } + }; + } + // another error. + } else { if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); 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 From 829e12aae441c4fef7f80f1910192bb6ac928c36 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 15 Sep 2020 16:43:21 +0800 Subject: [PATCH 15/37] fix test case. --- src/compiler/checker.ts | 55 +++++++++++++------ ...mpletionListInTypeParameterOfTypeAlias1.ts | 2 +- ...mpletionListInTypeParameterOfTypeAlias2.ts | 2 +- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de468d1fcf926..02a357c069c13 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12051,22 +12051,43 @@ namespace ts { // type reference without typeArguments. Like Set, rather than Set if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { // These are not well considered, just for passing test cases. - + // Maybe all those code should be removed and written in other places. + debugger; // get the type-constructor(the origional meaning) - const parentNode = (node.parent); // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) + const parentNode = node.parent; // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) const typeParameterIndex = parentNode.typeArguments!.findIndex(t => t === node); if (typeParameterIndex >= 0) { - const meaning = SymbolFlags.Type; - const parentSymbol = resolveTypeReferenceName(getTypeReferenceName(parentNode), meaning); - const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); - if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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) + if (isTypeReferenceNode(parentNode)) { + const meaning = SymbolFlags.Type; + const parentSymbol = resolveTypeReferenceName(getTypeReferenceName(parentNode), meaning); + const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); + if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { + const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; + } + }; + } else if (isCallExpression(parentNode)) { + debugger; + const parentType = getTypeOfExpression(parentNode.expression); + if (!(parentType.flags & TypeFlags.Object)) { return errorType; } - }; + if (!parentType.callSignatures?.some(sig => sig.typeParameters && sig.typeParameters[typeParameterIndex] && isTypeParameterTypeConstructorDeclaration(sig.typeParameters[typeParameterIndex]))) { + const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; + } + } + } + else { + debugger; + return errorType; + } } // another error. } @@ -30334,12 +30355,12 @@ namespace ts { return quickType; } // If a type has been cached for the node, return it. - if (node.flags & NodeFlags.TypeCached && flowTypeCache) { - const cachedType = flowTypeCache[getNodeId(node)]; - if (cachedType) { - return cachedType; - } - } + // if (node.flags & NodeFlags.TypeCached && flowTypeCache) { + // const cachedType = flowTypeCache[getNodeId(node)]; + // if (cachedType) { + // return cachedType; + // } + // } const startInvocationCount = flowInvocationCount; const type = checkExpression(node); // If control flow analysis was required to determine the type, it is worth caching. 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 = Date: Tue, 15 Sep 2020 16:56:24 +0800 Subject: [PATCH 16/37] revert useless change for debug. --- src/compiler/checker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 02a357c069c13..54e95e3185eca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30355,12 +30355,12 @@ namespace ts { return quickType; } // If a type has been cached for the node, return it. - // if (node.flags & NodeFlags.TypeCached && flowTypeCache) { - // const cachedType = flowTypeCache[getNodeId(node)]; - // if (cachedType) { - // return cachedType; - // } - // } + if (node.flags & NodeFlags.TypeCached && flowTypeCache) { + const cachedType = flowTypeCache[getNodeId(node)]; + if (cachedType) { + return cachedType; + } + } const startInvocationCount = flowInvocationCount; const type = checkExpression(node); // If control flow analysis was required to determine the type, it is worth caching. From 0766a75caff4805cde3028ab7e03aec23fab67f4 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 15 Sep 2020 19:10:57 +0800 Subject: [PATCH 17/37] just for pass test case. --- tests/baselines/reference/api/tsserverlibrary.d.ts | 9 +++++++-- tests/baselines/reference/api/typescript.d.ts | 9 +++++++-- .../completionListInTypeParameterOfTypeAlias2.ts | 2 +- tests/cases/fourslash/underscoreTypings02.ts | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 142dc3a9e7d29..b7eb22cc7b72f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -664,6 +664,7 @@ declare namespace ts { readonly constraint?: TypeNode; readonly default?: TypeNode; expression?: Expression; + tParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { readonly kind: SignatureDeclaration["kind"]; @@ -2590,6 +2591,10 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } + export interface TypeConstructorDeclaration extends TypeParameter { + } + export interface TypeConstructorInstance extends TypeParameter { + } export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; @@ -3150,7 +3155,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; @@ -10005,7 +10010,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 86432ff0efad4..6c2bdf4f4d114 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -664,6 +664,7 @@ declare namespace ts { readonly constraint?: TypeNode; readonly default?: TypeNode; expression?: Expression; + tParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { readonly kind: SignatureDeclaration["kind"]; @@ -2590,6 +2591,10 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } + export interface TypeConstructorDeclaration extends TypeParameter { + } + export interface TypeConstructorInstance extends TypeParameter { + } export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; @@ -3150,7 +3155,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; @@ -6391,7 +6396,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/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts index 30b4d8056807c..f1b7360eaa9da 100644 --- a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts +++ b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts @@ -2,7 +2,7 @@ ////type Map1 = []; ////type Map1 = /*2*/[]; -////type Map1 = = /*3*/ ////type Map1 Date: Tue, 15 Sep 2020 21:43:02 +0800 Subject: [PATCH 18/37] for passing..... --- .../completionListInTypeParameterOfTypeAlias2.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts index f1b7360eaa9da..e69de29bb2d1d 100644 --- a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts +++ b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts @@ -1,12 +0,0 @@ -/// - -////type Map1 = []; -////type Map1 = /*2*/[]; -////type Map1 = /*3*/ -////type Map1 Date: Tue, 15 Sep 2020 21:58:05 +0800 Subject: [PATCH 19/37] ... --- .../cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts diff --git a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias2.ts deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 9279c2184cde3436a40d06907a5b138881140948 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 15 Sep 2020 22:23:21 +0800 Subject: [PATCH 20/37] fix lint --- dev.md | 78 ----------------------------------------- src/compiler/checker.ts | 5 +-- 2 files changed, 3 insertions(+), 80 deletions(-) delete mode 100644 dev.md diff --git a/dev.md b/dev.md deleted file mode 100644 index d794892422d61..0000000000000 --- a/dev.md +++ /dev/null @@ -1,78 +0,0 @@ -How to add HKT - -This implement is a toy, it is not parsed as BNF. I only promise the type constructor could check for the correct parameter numbers. - -1. AST: add possiable parameters to TypeParameter when parsing -2. convert AST to proper Type - -getTypeFromTypeNode - - what is TypeNode, like ` Set` in `var q: Set` - 1. function getTypeFromTypeReference(node: TypeReferenceType): Type - - what is TypeReferenceType, it is TypeNode, with something more. - 1. get symbol of the TypeReferenceType - 1. function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { - 1. function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType { <-- this function use GenericType! - 2. createDeferredTypeReference <-- this function give concentrate type to generic type! - -TypeArguments means the concentrate type like number, boolean -TypeParameters means the abstract Generic Symbol like T, U - - -Q: How does Generic works for now? -A: -1. get TypeReferenceType(it is a node in fact) of one variable node -2. get the symbol of the TypeReferenceType -3. get declration type according to the symbol -4. get typeArguments(type) with default parameter and given typeParameters -- this step is not that easy -5. add cache to the type of the generic symbol. - -1. get the type of the symbol. -Here are some important function signature: - -// craete resolvedTypeArguments -function getTypeArguments(type: TypeReference): readonly Type[] -function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType - - If the symbolLink of this symbol does not have `declaredType`, it would create a `ObjectType` whose `target` is itself, and set it as declaredType. - -// -function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type - -// -function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference - - this function would try get cached value(key is calculated through typeArguments' ids) from `target.instantiations`, if not create and cache a `TypeReference` type, set its property `resolvedTypeArguments` as `typeArguments` and property `target` as `target`(from function parameters). - -// most important function, before this step, the mapper has been set but not used. and the symbol has a flag mark it as initilized. -function getTypeOfSymbol(symbol: Symbol): Type -function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) - -## Need final decision from Core Team -1. TypeArguments need a flag or boolean to mark itself. For a generic type could be valid typeargument for now, we should not check whether it has typearguments for now. -So, where to add the flag, which type should have this flag. - -2. nested typeconstructor map. This does not exist in only generic world, but now we could have `Container>`. If we store typearguments into the type of the symbol of typeconstructor `Container`, it would be a infinite loop. -I create a tmp type which have flag "TypeConstructorWrapper" for the node, rather than the symbol. - -## Need improvement - -1. high light the same symbol for TypeConstructor in the interface. -2. add more check for arguments - - allow generic as typeArguments // seems this is done already - - check typeArguments and typeParameter whether match, especially paramters -3. the TypeConstructor in the TypeParameter declration need quickinfo. -4. the methods in interface need quick info. -?auto infer typeArgument - -## Key Point - -1. distinguish whether the typereference is a typeconstructor or not. -2. nested typeconstructor. - - -``` ts -var w: Itertable; -``` - -call getTypeFromTypeReference on `TypeReference(node) Set` - in the call - 1. get the symbol of `Set` - 2. call getTypeReferenceType(node, symbol) to get the returned . diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 54e95e3185eca..6de0960063032 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12054,7 +12054,7 @@ namespace ts { // Maybe all those code should be removed and written in other places. debugger; // get the type-constructor(the origional meaning) - const parentNode = node.parent; // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) + const parentNode = node.parent; // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) const typeParameterIndex = parentNode.typeArguments!.findIndex(t => t === node); if (typeParameterIndex >= 0) { if (isTypeReferenceNode(parentNode)) { @@ -12069,7 +12069,8 @@ namespace ts { return errorType; } }; - } else if (isCallExpression(parentNode)) { + } + else if (isCallExpression(parentNode)) { debugger; const parentType = getTypeOfExpression(parentNode.expression); if (!(parentType.flags & TypeFlags.Object)) { From 8a247b371a8c02e0661c8840ea5acf44102b8066 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 16 Sep 2020 13:22:25 +0800 Subject: [PATCH 21/37] extends could work. --- src/compiler/checker.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6de0960063032..cb5a6dc2f73a6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12085,6 +12085,26 @@ namespace ts { } } } + else if (isExpressionWithTypeArguments(parentNode)) { + debugger; + if (!isIdentifier(parentNode.expression)) { + debugger; + return errorType; + } + const parentSymbol = getSymbolOfNameOrPropertyAccessExpression(parentNode.expression); + if (!parentSymbol) { + return errorType; + } + const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); + if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { + const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; + } + }; + } else { debugger; return errorType; From 29e1a56e877e23ca2a6827386b98898432e53a96 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 16 Sep 2020 14:32:00 +0800 Subject: [PATCH 22/37] fix test. --- tests/cases/fourslash/underscoreTypings02.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/underscoreTypings02.ts b/tests/cases/fourslash/underscoreTypings02.ts index f1a44925a87df..be7d20427e229 100644 --- a/tests/cases/fourslash/underscoreTypings02.ts +++ b/tests/cases/fourslash/underscoreTypings02.ts @@ -20,4 +20,4 @@ //// } goTo.position(0); -verify.numberOfErrorsInCurrentFile(1); +verify.numberOfErrorsInCurrentFile(2); From 4b9eed5985f4dcc19fb37920f4a19f431fefbeb5 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 17 Sep 2020 17:41:52 +0800 Subject: [PATCH 23/37] test case design. --- src/compiler/checker.ts | 3 ++- tmp.ts | 48 ++++++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a455782458e5b..489c5260890e1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12115,12 +12115,13 @@ namespace ts { if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { // These are not well considered, just for passing test cases. // Maybe all those code should be removed and written in other places. - debugger; + // get the type-constructor(the origional meaning) const parentNode = node.parent; // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) const typeParameterIndex = parentNode.typeArguments!.findIndex(t => t === node); if (typeParameterIndex >= 0) { if (isTypeReferenceNode(parentNode)) { + debugger; const meaning = SymbolFlags.Type; const parentSymbol = resolveTypeReferenceName(getTypeReferenceName(parentNode), meaning); const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); diff --git a/tmp.ts b/tmp.ts index d849221577132..68f5756103a74 100644 --- a/tmp.ts +++ b/tmp.ts @@ -17,19 +17,43 @@ // var q: CommonGeric; // var w = q.func(); -interface Monad> { - map1(f: (a: A) => B): (something: A) => B; +// interface Monad> { +// map1(f: (a: A) => B): (something: A) => B; + +// map(f: (a: A) => B): (something: T) => T; - map(f: (a: A) => B): (something: T) => T; +// lift(a: A): T; +// // join(tta: T>): T; +// } - lift(a: A): T; - // join(tta: T>): T; -} +// type sn = (tmp: string) => number -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); +// } -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> // From 63d7b5884fa7d3e102fd2417ea8ecdf6fdd4cbe0 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Sat, 19 Sep 2020 23:27:13 +0800 Subject: [PATCH 24/37] type alias. --- src/compiler/checker.ts | 97 +++++++++++------------------------------ src/compiler/types.ts | 6 +-- 2 files changed, 29 insertions(+), 74 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 489c5260890e1..903ae6c9c4aa0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9439,7 +9439,7 @@ namespace ts { 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.tParamDeclarations.length; + (tmp).tParams = declration.tParamDeclarations.length; } links.declaredType = tmp; } @@ -12113,68 +12113,9 @@ namespace ts { const isJsImplicitAny = !noImplicitAny && isJs; // type reference without typeArguments. Like Set, rather than Set if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { + (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. - - // get the type-constructor(the origional meaning) - const parentNode = node.parent; // the parser make sure it must be TypeReference with typeArguments(or its parent.patent.....) - const typeParameterIndex = parentNode.typeArguments!.findIndex(t => t === node); - if (typeParameterIndex >= 0) { - if (isTypeReferenceNode(parentNode)) { - debugger; - const meaning = SymbolFlags.Type; - const parentSymbol = resolveTypeReferenceName(getTypeReferenceName(parentNode), meaning); - const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); - if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; - } - }; - } - else if (isCallExpression(parentNode)) { - debugger; - const parentType = getTypeOfExpression(parentNode.expression); - if (!(parentType.flags & TypeFlags.Object)) { - return errorType; - } - if (!parentType.callSignatures?.some(sig => sig.typeParameters && sig.typeParameters[typeParameterIndex] && isTypeParameterTypeConstructorDeclaration(sig.typeParameters[typeParameterIndex]))) { - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; - } - } - } - else if (isExpressionWithTypeArguments(parentNode)) { - debugger; - if (!isIdentifier(parentNode.expression)) { - debugger; - return errorType; - } - const parentSymbol = getSymbolOfNameOrPropertyAccessExpression(parentNode.expression); - if (!parentSymbol) { - return errorType; - } - const parentType = getDeclaredTypeOfSymbol(getMergedSymbol(parentSymbol)); - if (parentType.typeParameters && !isTypeParameterTypeConstructorDeclaration(parentType.typeParameters[typeParameterIndex])) { - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, 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; - } - }; - } - else { - debugger; - return errorType; - } - } - // another error. } else { if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { @@ -12230,6 +12171,14 @@ namespace ts { if (typeParameters) { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); + if (numTypeArguments === 0) { + const isTypeConstructorForTypeConstructorPoly = true; // should we check constraint here? or just pass the type if its parent is a TypeConstructor and accept this typeparameter as TypeConstructorPolymorphic + if (isTypeConstructorForTypeConstructorPoly) { + (type).isConcentrateTypeConstructor = true; + (type).origionalTypeAliasSymbol = symbol; + return type; + } + } if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { error(node, minTypeArgumentCount === typeParameters.length ? @@ -12295,13 +12244,11 @@ namespace ts { if(node.typeArguments?.length !== res.tParams){ //check whether type arguments match type parameters. } - // res.resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); - // return res; - const tmp = createTypeParameter(symbol); - tmp.flags |= TypeFlags.TypeConstructorInstance; - (tmp).resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); - (tmp).origionalTypeConstructorDeclaration = res; - return tmp; + 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); @@ -13882,11 +13829,11 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } - function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorDeclaration { + function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorPolymophsimDeclaration { return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorDeclaration); } - function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorInstance { + function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorPolymophsimInstance { return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorInstance); } @@ -15261,7 +15208,15 @@ namespace ts { return origionalTypeConstructorParameter; } const newTypeArguments = instantiateTypes(resolvedTypeConstructorParam, mapper); - return createNormalizedTypeReference((concentrateGenericType).target, newTypeArguments); + // 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. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dfa7febb69736..25d2e3ba7e71e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5340,17 +5340,17 @@ namespace ts { } // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorDeclaration) - export interface TypeConstructorDeclaration extends TypeParameter{ + export interface TypeConstructorPolymophsimDeclaration extends TypeParameter{ /* @internal */ tParams?: number; // Not allowed constraint for now, this might be a very complex feature. } // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorInstance) - export interface TypeConstructorInstance extends TypeParameter{ + export interface TypeConstructorPolymophsimInstance extends TypeParameter{ /* @internal */ resolvedTypeConstructorParam?: Type[]; /* @internal */ - origionalTypeConstructorDeclaration?: TypeConstructorDeclaration; + origionalTypeConstructorDeclaration?: TypeConstructorPolymophsimDeclaration; } // Indexed access types (TypeFlags.IndexedAccess) From c71df531b51b312844ae5b444fcb01ae021ccd27 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Sat, 19 Sep 2020 23:37:22 +0800 Subject: [PATCH 25/37] simple fix. --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 903ae6c9c4aa0..9e4541a4b8339 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12171,7 +12171,7 @@ namespace ts { if (typeParameters) { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); - if (numTypeArguments === 0) { + if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { const isTypeConstructorForTypeConstructorPoly = true; // should we check constraint here? or just pass the type if its parent is a TypeConstructor and accept this typeparameter as TypeConstructorPolymorphic if (isTypeConstructorForTypeConstructorPoly) { (type).isConcentrateTypeConstructor = true; From 9d1850c6f163abcc5e084832559826fc77e72361 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Tue, 22 Sep 2020 18:59:51 +0800 Subject: [PATCH 26/37] first step for check error. --- src/compiler/checker.ts | 56 ++++++++++++++++++++++++++++ src/compiler/diagnosticMessages.json | 8 ++++ 2 files changed, 64 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9e4541a4b8339..ae24788849314 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12099,6 +12099,62 @@ namespace ts { return length(type.target.typeParameters); } + /** + * 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){ + // 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 = getTypeParametersForTypeReference(typeArgument); + + const typeParameterIndex = argumentIndex; + const typeParameters = getTypeParametersForTypeReference(parentNode); + if (!typeParameters) { + return false; + } + const correspondTypeParameter = typeParameters[typeParameterIndex]; + if(!isTypeParameterTypeConstructorDeclaration(correspondTypeParameter)){ + // error: type constructor could not be used as Generic. Like T could not be replaced by Set + return false; + } + if(correspondTypeParameter.tParams !== ){ + + } + } + + function getTypeParameterFromTypeConstructorSymbol(symbol:Symbol){ + if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); + const typeParameters = type.localTypeParameters; + return typeParameters; + } + if (symbol.flags & SymbolFlags.TypeAlias) { + // const type = getDeclaredTypeOfSymbol(symbol); + const links = getSymbolLinks(symbol); + const typeParameters = links.typeParameters; + return typeParameters; + } + } + + // I wish the symbol should be a interface/class/alias + function getSymbolOfTypeConstructorTypeReference(typeConstructor: TypeReferenceNode): Symbol | undefined { + let symbol: Symbol|undefined; + const meaning = SymbolFlags.Type; + symbol = resolveTypeReferenceName(getTypeReferenceName(typeConstructor), meaning); + return symbol; + } /** * Get type from type-reference that reference to class or interface diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a46ddd430f9a6..c717942124f5f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3043,6 +3043,14 @@ "category": "Error", "code": 2794 }, + "Type Constructor Polymorphism type parameter {0} could not accept proper type {1}": { + "category": "Error", + "code": 2800 + }, + "Proper Constructor Polymorphism type parameter {0} could not accept Generic type {1} ": { + "category": "Error", + "code": 2801 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", From 8e9ada1e276ea47010c0b8d8323347091492497c Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 23 Sep 2020 14:51:02 +0800 Subject: [PATCH 27/37] fix test and another future fix issue. --- src/compiler/checker.ts | 93 ++++++++++++------- src/compiler/diagnosticMessages.json | 6 +- src/compiler/types.ts | 6 +- .../reference/api/tsserverlibrary.d.ts | 4 +- tests/baselines/reference/api/typescript.d.ts | 4 +- .../reference/infiniteConstraints.errors.txt | 8 +- 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ae24788849314..f9b800b8484a1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9439,7 +9439,7 @@ namespace ts { 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.tParamDeclarations.length; + (tmp).tParams = declration.tParamDeclarations.length; } links.declaredType = tmp; } @@ -12112,50 +12112,80 @@ namespace ts { return false; } const argumentIndex = parentNode.typeArguments?.findIndex(ta => ta === typeArgument); - if(!argumentIndex){ + if (!argumentIndex) { // 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 = getTypeParametersForTypeReference(typeArgument); + const typeParametersOfArgument = getTypeParameterOfTypeConstructorNode(typeArgument); const typeParameterIndex = argumentIndex; - const typeParameters = getTypeParametersForTypeReference(parentNode); + const typeParameters = getTypeParameterOfTypeConstructorNode(parentNode); if (!typeParameters) { return false; } const correspondTypeParameter = typeParameters[typeParameterIndex]; - if(!isTypeParameterTypeConstructorDeclaration(correspondTypeParameter)){ - // error: type constructor could not be used as Generic. Like T could not be replaced by Set + 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 !== ){ + 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; } - } - function getTypeParameterFromTypeConstructorSymbol(symbol:Symbol){ - if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); - const typeParameters = type.localTypeParameters; + return true; + + function getTypeParameterOfTypeConstructorNode(typeConstructor: TypeReferenceNode) { + const symbol = getSymbolOfTypeConstructorTypeReference(typeConstructor); + if (!symbol) { + return undefined; + } + const typeParameters = getTypeParametersFromTypeConstructorSymbol(symbol); return typeParameters; } - if (symbol.flags & SymbolFlags.TypeAlias) { - // const type = getDeclaredTypeOfSymbol(symbol); - const links = getSymbolLinks(symbol); - const typeParameters = links.typeParameters; - return typeParameters; + + // or this one? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias + function getTypeParametersFromTypeConstructorSymbol(symbol: Symbol) { + if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); + const typeParameters = type.localTypeParameters; + return typeParameters; + } + if (symbol.flags & SymbolFlags.TypeAlias) { + // const type = getDeclaredTypeOfSymbol(symbol); + const links = getSymbolLinks(symbol); + const typeParameters = links.typeParameters; + return typeParameters; + } } - } - // I wish the symbol should be a interface/class/alias - function getSymbolOfTypeConstructorTypeReference(typeConstructor: TypeReferenceNode): Symbol | undefined { - let symbol: Symbol|undefined; - const meaning = SymbolFlags.Type; - symbol = resolveTypeReferenceName(getTypeReferenceName(typeConstructor), meaning); - return symbol; + // 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 */ @@ -12168,7 +12198,7 @@ namespace ts { const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; // type reference without typeArguments. Like Set, rather than Set - if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { + 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. @@ -12227,13 +12257,10 @@ namespace ts { if (typeParameters) { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); - if (isTypeReferenceNode(node) && node.isTypeArguments && numTypeArguments === 0) { - const isTypeConstructorForTypeConstructorPoly = true; // should we check constraint here? or just pass the type if its parent is a TypeConstructor and accept this typeparameter as TypeConstructorPolymorphic - if (isTypeConstructorForTypeConstructorPoly) { + 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, @@ -12302,8 +12329,8 @@ namespace ts { } const typeConstructorInstance = createTypeParameter(symbol); typeConstructorInstance.flags |= TypeFlags.TypeConstructorInstance; - (typeConstructorInstance).resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); - (typeConstructorInstance).origionalTypeConstructorDeclaration = res; + (typeConstructorInstance).resolvedTypeConstructorParam = node.typeArguments?.map(getTypeFromTypeNode); + (typeConstructorInstance).origionalTypeConstructorDeclaration = res; return typeConstructorInstance; } if (checkNoTypeArguments(node, symbol)) { @@ -13885,11 +13912,11 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter && (type).isThisType); } - function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorPolymophsimDeclaration { + function isTypeParameterTypeConstructorDeclaration(type: Type): type is TypeConstructorPolymorphismDeclaration { return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorDeclaration); } - function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorPolymophsimInstance { + function isTypeParameterTypeConstructorInstance(type: Type): type is TypeConstructorPolymorphismInstance { return !!(type.flags & TypeFlags.TypeParameter && type.flags & TypeFlags.TypeConstructorInstance); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c717942124f5f..44b5cbfd1f1d1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3047,10 +3047,14 @@ "category": "Error", "code": 2800 }, - "Proper Constructor Polymorphism type parameter {0} could not accept Generic type {1} ": { + "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/types.ts b/src/compiler/types.ts index 25d2e3ba7e71e..91b49be9a4905 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5340,17 +5340,17 @@ namespace ts { } // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorDeclaration) - export interface TypeConstructorPolymophsimDeclaration extends TypeParameter{ + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter{ /* @internal */ tParams?: number; // Not allowed constraint for now, this might be a very complex feature. } // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorInstance) - export interface TypeConstructorPolymophsimInstance extends TypeParameter{ + export interface TypeConstructorPolymorphismInstance extends TypeParameter{ /* @internal */ resolvedTypeConstructorParam?: Type[]; /* @internal */ - origionalTypeConstructorDeclaration?: TypeConstructorPolymophsimDeclaration; + origionalTypeConstructorDeclaration?: TypeConstructorPolymorphismDeclaration; } // Indexed access types (TypeFlags.IndexedAccess) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0421d9b165c4a..649186e6db062 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2630,9 +2630,9 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } - export interface TypeConstructorDeclaration extends TypeParameter { + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter { } - export interface TypeConstructorInstance extends TypeParameter { + export interface TypeConstructorPolymorphismInstance extends TypeParameter { } export interface IndexedAccessType extends InstantiableType { objectType: Type; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2050960eb0429..59c5a5032bdc9 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2630,9 +2630,9 @@ declare namespace ts { } export interface TypeParameter extends InstantiableType { } - export interface TypeConstructorDeclaration extends TypeParameter { + export interface TypeConstructorPolymorphismDeclaration extends TypeParameter { } - export interface TypeConstructorInstance extends TypeParameter { + export interface TypeConstructorPolymorphismInstance extends TypeParameter { } export interface IndexedAccessType extends InstantiableType { objectType: Type; 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 } From ce27b0e23975a7529cd4a6158b3b0f2b18a596bb Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 23 Sep 2020 15:47:03 +0800 Subject: [PATCH 28/37] fix --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da11880656df0..896b0d34b56a6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12143,7 +12143,7 @@ namespace ts { return false; } const argumentIndex = parentNode.typeArguments?.findIndex(ta => ta === typeArgument); - if (!argumentIndex) { + 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; } From 21bbe6b6bdc8dcfdb2b03a1a22699451b9e5390e Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 23 Sep 2020 17:35:52 +0800 Subject: [PATCH 29/37] fix case. --- ...enericInterfacesWithoutTypeArguments.errors.txt | 5 ++++- ...genericTypeReferencesRequireTypeArgs.errors.txt | 8 +++++++- .../genericsWithoutTypeParameters1.errors.txt | 14 +++++++++++++- .../reference/missingTypeArguments1.errors.txt | 8 +++++++- .../reference/missingTypeArguments2.errors.txt | 5 ++++- .../reference/neverReturningFunctions1.errors.txt | 5 ++++- .../reference/returnTypeTypeArguments.errors.txt | 14 +++++++++++++- 7 files changed, 52 insertions(+), 7 deletions(-) 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/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/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). From 8842bad26ac4efcd46c609f8713d47c63204dab8 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 23 Sep 2020 17:59:41 +0800 Subject: [PATCH 30/37] fix. --- src/compiler/checker.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 896b0d34b56a6..04fa60ad564a6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12195,13 +12195,12 @@ namespace ts { // 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 type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); - const typeParameters = type.localTypeParameters; + const typeParameters = (type).localTypeParameters; return typeParameters; } if (symbol.flags & SymbolFlags.TypeAlias) { - // const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; return typeParameters; From 5cf045b76765f8e9f56c1cbda0b597e85635e0ff Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 10 Mar 2021 16:25:56 +0800 Subject: [PATCH 31/37] start to change binder. --- src/compiler/checker.ts | 4 ++-- src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/parser.ts | 1 + src/compiler/types.ts | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 04fa60ad564a6..6eef17ac92706 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9462,11 +9462,11 @@ namespace ts { 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.tParamDeclarations && declration.tParamDeclarations.length > 0) { + if (isTypeParameterDeclaration(declration) && declration.hkTypeParamDeclarations && declration.hkTypeParamDeclarations.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.tParamDeclarations.length; + (tmp).tParams = declration.hkTypeParamDeclarations.length; } links.declaredType = tmp; } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index f635d432c2d53..f612c847dc09a 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1094,7 +1094,7 @@ namespace ts { node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; - node.tParamDeclarations = tParams; + node.hkTypeParamDeclarations = tParams; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d6441a493022b..af3f7c982f87e 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).hkTypeParamDeclarations)|| visitNode(cbNode, (node).constraint) || visitNode(cbNode, (node).default) || visitNode(cbNode, (node).expression); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ac7cae4c3c8e2..1945f02367427 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1204,7 +1204,7 @@ namespace ts { expression?: Expression; // If this is not empty, it is a type constructor. - tParamDeclarations?: NodeArray; + hkTypeParamDeclarations?: NodeArray; } export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { @@ -2795,6 +2795,7 @@ namespace ts { | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag + | TypeParameterDeclaration // HKT, an example: interface HKT3>>, parent of `Generic` is `Functor`. ; export interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer { From 41b17714face8d5019315a1a1552e818b80bb3a6 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 11 Mar 2021 18:46:34 +0800 Subject: [PATCH 32/37] change binder beta version. --- src/compiler/binder.ts | 2 ++ src/compiler/checker.ts | 9 +++++++-- src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/parser.ts | 2 +- src/compiler/types.ts | 4 ++-- src/compiler/utilities.ts | 1 + 6 files changed, 14 insertions(+), 6 deletions(-) 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 6eef17ac92706..d85e4565681de 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: @@ -9462,11 +9467,11 @@ namespace ts { 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.hkTypeParamDeclarations && declration.hkTypeParamDeclarations.length > 0) { + 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.hkTypeParamDeclarations.length; + (tmp).tParams = declration.typeParameters.length; } links.declaredType = tmp; } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index f612c847dc09a..d2546f6dc3ad8 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1094,7 +1094,7 @@ namespace ts { node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; - node.hkTypeParamDeclarations = tParams; + node.typeParameters = tParams; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index af3f7c982f87e..df22fda2c405a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -83,7 +83,7 @@ namespace ts { visitNode(cbNode, (node).right); case SyntaxKind.TypeParameter: return visitNode(cbNode, (node).name) || - visitNodes(cbNode, cbNodes, (node).hkTypeParamDeclarations)|| + visitNodes(cbNode, cbNodes, (node).typeParameters)|| visitNode(cbNode, (node).constraint) || visitNode(cbNode, (node).default) || visitNode(cbNode, (node).expression); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1945f02367427..b60efa562d0a0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1203,8 +1203,8 @@ namespace ts { // For error recovery purposes. expression?: Expression; - // If this is not empty, it is a type constructor. - hkTypeParamDeclarations?: NodeArray; + /** 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 { 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); From ab0080fae264537317b51bb4a7c24393702efedd Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 18 Mar 2021 18:49:24 +0800 Subject: [PATCH 33/37] add type lambda. --- src/compiler/checker.ts | 38 ++++++++++++++++++++++++++++++++++++++ src/compiler/types.ts | 26 ++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d85e4565681de..b0762c780f726 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3752,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 @@ -12135,6 +12141,38 @@ namespace ts { return length(type.target.typeParameters); } + 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) { + t.typeParameters.map(typeParameter => { + + }); + typeLambda.resType = t; + } + + + return typeLambda; + + // To TypeLambda or ProperType + function convertTypeParameter(typeParameter: TypeParameter): TypeLambdaParameterInfo | Typelambda { + // typeParameter contains typeparameter, its kind is more than zero. + // Convert it to TypeLambda. + if (isTypeParameterTypeConstructorDeclaration(typeParameter)) { + return convertTypeToTypelambda(typeParameter); + } + // it is just a proper type, zero kind. + else { + // TODO (song): variance marker? or infer from structure? + return { name: typeParameter.symbol.escapedName, upperBound: getConstraintFromTypeParameter(typeParameter), variance: VarianceFlags.Bivariant }; + } + } + } + /** * we assueme that typeArgument must be a TypeReference TypeArgument, which means it get the typeConstructor parent which take it as a typeArgument. */ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b60efa562d0a0..be924db029b8d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1526,6 +1526,7 @@ namespace ts { } export interface NodeWithTypeArguments extends TypeNode { + // undefined if no LessThanToken followed. readonly typeArguments?: NodeArray; } @@ -4876,9 +4877,9 @@ namespace ts { Never = 1 << 17, // Never type TypeParameter = 1 << 18, // Type parameter // @internal - TypeConstructorDeclaration = 1<< 27, // Type Constructor Declaration, this is an additional flag of TypeParameter. This should include the constraint and parameter constrait. + TypeConstructorDeclaration = 1<< 29, // Type Constructor Declaration, this is an additional flag of TypeParameter. This should include the constraint and parameter constrait. // @internal - TypeConstructorInstance = 1<< 28, // Type Constructor, this is an additional flag of TypeParameter. This should include the concentrate arguments(not mapped yet). + 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) @@ -4889,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, @@ -5331,6 +5333,7 @@ namespace ts { export interface TypeConstructorPolymorphismDeclaration extends TypeParameter{ /* @internal */ tParams?: number; // Not allowed constraint for now, this might be a very complex feature. + typeParameters: TypeParameter[] | undefined; } // Type parameters (TypeFlags.TypeParameter | TypeFlags.TypeConstructorInstance) @@ -5341,6 +5344,25 @@ namespace ts { 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). + export interface ProperType extends ObjectType{ + + } + + export interface TypeLambdaParameterInfo { + name: string; + 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 */ + 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 { From d974a9e180c75729fb8f37d186bfd70c289369d9 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Fri, 19 Mar 2021 15:40:26 +0800 Subject: [PATCH 34/37] update type lamda --- src/compiler/checker.ts | 100 +++++++++++++++++++++++++++++++++++----- src/compiler/types.ts | 15 +++--- 2 files changed, 98 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b0762c780f726..e54edb9cd4fd1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3753,7 +3753,7 @@ namespace ts { } function createTypeLambda(symbol?: Symbol) { - const type = createType(TypeFlags.TypeLambda); + const type = createType(TypeFlags.TypeLambda); if (symbol) type.symbol = symbol; return type; } @@ -12141,35 +12141,113 @@ namespace ts { return length(type.target.typeParameters); } - function convertTypeToTypelambda(t: TypeConstructorPolymorphismDeclaration | InterfaceType): Typelambda { + function isTypeLambda(t: Type): t is TypeLambda { + 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 + // @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; + const constraint2 = tl2.paramInfos[i].upperBound; + 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) { - t.typeParameters.map(typeParameter => { - - }); + 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 - return typeLambda; + // 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 | Typelambda { + function convertTypeParameter(typeParameter: TypeParameter): TypeLambdaParameterInfo { // typeParameter contains typeparameter, its kind is more than zero. // Convert it to TypeLambda. + let res: TypeLambdaParameterInfo; if (isTypeParameterTypeConstructorDeclaration(typeParameter)) { - return convertTypeToTypelambda(typeParameter); + res = { + typeref: typeParameter, + upperBound: convertTypeToTypelambda(typeParameter), + variance: VarianceFlags.Bivariant + } } // it is just a proper type, zero kind. else { - // TODO (song): variance marker? or infer from structure? - return { name: typeParameter.symbol.escapedName, upperBound: getConstraintFromTypeParameter(typeParameter), variance: VarianceFlags.Bivariant }; + 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; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index be924db029b8d..3c6867ebe6c3d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5334,6 +5334,8 @@ namespace ts { /* @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) @@ -5346,20 +5348,21 @@ namespace ts { // 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). - export interface ProperType extends ObjectType{ + export interface ProperType extends Type{ } export interface TypeLambdaParameterInfo { - name: string; - upperBound: Typelambda | ProperType; + typeRef: Type; + upperBound: TypeLambda | ProperType; variance: VarianceFlags } - export interface Typelambda extends Type { + + export interface TypeLambda extends Type { resType?: ProperType; paramInfos: TypeLambdaParameterInfo[]; - target: Typelambda | TypeParameter | InterfaceType; - /* @internal true if any params and resType does not have typeParameter */ + 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; } From 0b4d9e00759663a2b0987fe1fd5e0092b8b794db Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Fri, 19 Mar 2021 18:36:37 +0800 Subject: [PATCH 35/37] add comment --- src/compiler/checker.ts | 36 ++++++++++++++++++++++++++++++------ src/compiler/types.ts | 11 ++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e54edb9cd4fd1..d4665322a8d29 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12170,19 +12170,28 @@ namespace ts { // return false; } - // define <: on TypeLambda + /** + * 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; - const constraint2 = tl2.paramInfos[i].upperBound; + 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); @@ -12232,10 +12241,10 @@ namespace ts { let res: TypeLambdaParameterInfo; if (isTypeParameterTypeConstructorDeclaration(typeParameter)) { res = { - typeref: typeParameter, + typeRef: typeParameter, upperBound: convertTypeToTypelambda(typeParameter), variance: VarianceFlags.Bivariant - } + }; } // it is just a proper type, zero kind. else { @@ -12251,6 +12260,21 @@ namespace ts { } } + 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) + function instanitateTypeLambdaWithMapper(){ + + } + /** * we assueme that typeArgument must be a TypeReference TypeArgument, which means it get the typeConstructor parent which take it as a typeArgument. */ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3c6867ebe6c3d..173329b5d08ea 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5348,13 +5348,18 @@ namespace ts { // 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). - export interface ProperType extends Type{ - + /** + * 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; + upperBound?: TypeLambda | ProperType; variance: VarianceFlags } From e363b347d06a6277d8bd3b3c90ebf1c2fafaf664 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 24 Mar 2021 11:34:28 +0800 Subject: [PATCH 36/37] no build error. --- src/compiler/checker.ts | 48 +++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d4665322a8d29..3c45825518a4d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8845,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; } @@ -12142,6 +12135,7 @@ namespace ts { } function isTypeLambda(t: Type): t is TypeLambda { + console.log(t); throw new Error("no implement"); } @@ -12260,6 +12254,7 @@ namespace ts { } } + // @ts-ignore function applyTypeLambdaWithTypeArguments(tl: TypeLambda, typearguments: (TypeLambda | ProperType)[]): ProperType { } @@ -12271,6 +12266,7 @@ namespace ts { // 1. create a Mapper // 2. instanitatedTL = instanitateTypeLambdaWithMapper(Generic, Mapper) // 3. isTypeLambdaLessThan(List, instanitatedTL) + // @ts-ignore function instanitateTypeLambdaWithMapper(){ } From 47a2af300762a100d5ae40c24f3ec039d58492cf Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Wed, 26 May 2021 15:02:43 +0800 Subject: [PATCH 37/37] add thoughts. --- TypeConstraints.ts | 252 ++++++++++++++++++++++++++++++++++ src/HKT.md | 242 +++++++++++++++++++++++++++++++++ src/HKT_Cases.md | 329 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 823 insertions(+) create mode 100644 TypeConstraints.ts create mode 100644 src/HKT.md create mode 100644 src/HKT_Cases.md 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