Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type relationship functions to checker public api #9943

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ var harnessSources = harnessCoreSources.concat([
"transpile.ts",
"reuseProgramStructure.ts",
"textStorage.ts",
"checkerPublicRelationships.ts",
"moduleResolution.ts",
"tsconfigParsing.ts",
"builder.ts",
Expand Down
44 changes: 44 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,50 @@ namespace ts {
return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false);
},
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),

isIdenticalTo: (a, b) => checkTypeRelatedTo(a, b, identityRelation, /*errorNode*/ undefined),
isSubtypeOf: (a, b) => checkTypeRelatedTo(a, b, subtypeRelation, /*errorNode*/ undefined),
isAssignableTo: (a, b) => checkTypeRelatedTo(a, b, assignableRelation, /*errorNode*/ undefined),
isComparableTo: areTypesComparable,
isInstantiationOf: (a, b) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this one i would say.

return a && b && (a.target === b);
},

lookupGlobalType: name => {
const symbol = getSymbol(globals, escapeLeadingUnderscores(name), SymbolFlags.Type);
return symbol ? getDeclaredTypeOfSymbol(symbol) : unknownType;
},
lookupGlobalValueType: name => {
const symbol = getSymbol(globals, escapeLeadingUnderscores(name), SymbolFlags.Value);
return symbol ? getTypeOfSymbol(symbol) : unknownType;
},
lookupTypeAt: (name, node) => {
const symbol = resolveName(node, escapeLeadingUnderscores(name), SymbolFlags.Type, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false);
return symbol ? getDeclaredTypeOfSymbol(symbol) : unknownType;
},
lookupValueTypeAt: (name, node) => {
const symbol = resolveName(node, escapeLeadingUnderscores(name), SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false);
return symbol ? getTypeOfSymbol(symbol) : unknownType;
},
getTypeOfSymbol,
getUnknownType: () => unknownType,
getStringLiteralType: (text: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging these two into one getLiteralType

/* tslint:disable:no-null-keyword */
Debug.assert(text !== undefined && text !== null, "Argument to getStringLiteralType was null or undefined");
/* tslint:enable:no-null-keyword */
Debug.assert(typeof text === "string", "Argument to getStringLiteralType not a string");
return getLiteralType(text);
},
getNumberLiteralType: (num: number) => {
/* tslint:disable:no-null-keyword */
Debug.assert(num !== undefined && num !== null, "Argument to getNumberLiteralType was null or undefined");
/* tslint:enable:no-null-keyword */
Debug.assert(typeof num === "number", "Argument to getStringLiteralType not a number");
return getLiteralType(num);
},
getFalseType: () => falseType,
getTrueType: () => trueType,
getNonPrimitiveType: () => nonPrimitiveType,
};

const tupleTypes: GenericType[] = [];
Expand Down
105 changes: 96 additions & 9 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2725,15 +2725,6 @@ namespace ts {
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
/* @internal */ getBaseConstraintOfType(type: Type): Type | undefined;

/* @internal */ getAnyType(): Type;
/* @internal */ getStringType(): Type;
/* @internal */ getNumberType(): Type;
/* @internal */ getBooleanType(): Type;
/* @internal */ getVoidType(): Type;
/* @internal */ getUndefinedType(): Type;
/* @internal */ getNullType(): Type;
/* @internal */ getESSymbolType(): Type;
/* @internal */ getNeverType(): Type;
/* @internal */ getUnionType(types: Type[], subtypeReduction?: boolean): Type;
/* @internal */ createArrayType(elementType: Type): Type;
/* @internal */ createPromiseType(type: Type): Type;
Expand All @@ -2745,8 +2736,104 @@ namespace ts {
/* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult;
/* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined;


/* @internal */ getSymbolWalker(accept?: (symbol: Symbol) => boolean): SymbolWalker;

/**
* Two types are considered identical when
* - they are both the `any` type,
* - they are the same primitive type,
* - they are the same type parameter,
* - they are union types with identical sets of constituent types, or
* - they are intersection types with identical sets of constituent types, or
* - they are object types with identical sets of members.
*
* This relationship is bidirectional.
* See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.2) for more information.
*/
isIdenticalTo(a: Type, b: Type): boolean;
/**
* `a` is a ___subtype___ of `b` (and `b` is a ___supertype___ of `a`) if `a` has no excess properties with respect to `b`,
* and one of the following is true:
* - `a` and `b` are identical types.
* - `b` is the `any` type.
* - `a` is the `undefined` type.
* - `a` is the `null` type and `b` is _not_ the `undefined` type.
* - `a` is an enum type and `b` is the primitive type `number`.
* - `a` is a string literal type and `b` is the primitive type `string`.
* - `a` is a union type and each constituient type of `b` is a subtype of `b`.
* - `a` is an intersection type and at least one constituent type of `a` is a subtype of `b`.
* - `b` is a union type and `a` is a subtype of at least one constituent type of `b`.
* - `b` is an intersection type and `a` is a subtype of each constituent type of `b`.
* - `a` is a type parameter and the constraint of `a` is a subtype of `b`.
* - `a` has a subset of the structural members of `b`.
*
* This relationship is directional.
* See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.3) for more information.
*/
isSubtypeOf(a: Type, b: Type): boolean;
/**
* The assignable relationship differs only from the subtype relationship in that:
* - the `any` type is assignable to, but not a subtype of, all types
* - the primitive type `number` is assignable to, but not a subtype of, all enum types, and
* - an object type without a particular property is assignable to an object type in which that property is optional.
*
* This relationship is directional.
* See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.4) for more information.
*/
isAssignableTo(a: Type, b: Type): boolean;
/**
* True if `a` is assignable to `b`, or `b` is assignable to `a`. Additionally, all unions with
* overlapping constituient types are comparable, and unit types in the same domain are comparable.
* This relationship is bidirectional.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relationship is not bidirectional; at least not right now. You probably wanted to use areTypesComparable.

It still feels strange that the other two are unidirectional but not this one.

Copy link
Member Author

@weswigham weswigham Jul 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subtype and assignable are directional, while identical should be nondirectional. comparable is really only useful when you consider it as nondirectional, no? (Also, fixed: now uses areTypesComparable. Thanks, I wasn't aware that such a function existed outside of checkTypesRelatedTo)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bidirectionality falls out of reflexivity in the identical relationship.

Unidirectional comparability is more like a possibly-satisfies relationship, and if one type satisfies another in either direction, we consider those types comparable. I don't know if there is a good use case outside of comparison.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPossiblyComparableTo sounds like a poor relationship to expose. IMO, just exposing areTypesComparable as isComparableTo seems better. I also cannot think of a case where you'd only want the possibly-comparable form.

*/
isComparableTo(a: Type, b: Type): boolean;
/**
* Not a formal relationship - returns true if a is an instantiation of the generic type b
*/
isInstantiationOf(a: GenericType, b: GenericType): boolean;

/**
* Returns the declared type of the globally named symbol with meaning SymbolFlags.Type
* Returns the unknown type on failure.
*/
lookupGlobalType(name: string): Type;
/**
* Returns the declared type of the globally named symbol with meaning SymbolFlags.Value
* Returns the unknown type on failure.
*/
lookupGlobalValueType(name: string): Type;
/**
* Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Type
* Returns the unknown type on failure.
*/
lookupTypeAt(name: string, position: Node): Type;
/**
* Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Value
* Returns the unknown type on failure.
*/
lookupValueTypeAt(name: string, position: Node): Type;
/**
* Returns the type of a symbol
*/
getTypeOfSymbol(symbol: Symbol): Type;

getAnyType(): Type;
getStringType(): Type;
getNumberType(): Type;
getBooleanType(): Type;
getVoidType(): Type;
getUndefinedType(): Type;
getNullType(): Type;
getESSymbolType(): Type;
getNeverType(): Type;
getUnknownType(): Type;
getStringLiteralType(text: string): LiteralType;
getNumberLiteralType(num: number): LiteralType;
getFalseType(): Type;
getTrueType(): Type;
getNonPrimitiveType(): Type;

// Should not be called directly. Should only be accessed through the Program instance.
/* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
/* @internal */ getGlobalDiagnostics(): Diagnostic[];
Expand Down
1 change: 1 addition & 0 deletions src/harness/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"./unittests/convertToBase64.ts",
"./unittests/transpile.ts",
"./unittests/reuseProgramStructure.ts",
"./unittests/checkerPublicRelationships.ts",
"./unittests/moduleResolution.ts",
"./unittests/tsconfigParsing.ts",
"./unittests/builder.ts",
Expand Down
Loading