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

Adds support for type parameter defaults #13487

Merged
merged 23 commits into from
Feb 15, 2017
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3d3dae0
Adds support for type parameter defaults
rbuckton Jan 14, 2017
442f540
Updated Promise and PromiseLike to use defaults
rbuckton Jan 14, 2017
25cb02e
Fix circularity check, simplify default type mapper
rbuckton Jan 14, 2017
ca16ba8
Added comments and additional circularity tests
rbuckton Jan 14, 2017
0b44a2c
Flexible declaration merging
rbuckton Jan 19, 2017
0500065
Avoid inference for fully-supplied type arguments
rbuckton Jan 20, 2017
5ff0f81
Diagnostic message punctuation
rbuckton Jan 20, 2017
a2be5e2
Report error using type parameter from merged declaration
rbuckton Jan 21, 2017
fd228a9
Remove partial inference
rbuckton Jan 21, 2017
6b2c8cb
Defaults for type aliases
rbuckton Jan 21, 2017
76ba6a7
Merge branch 'master' into genericDefaults
rbuckton Jan 21, 2017
15232fe
Remove circular default check
rbuckton Jan 24, 2017
f5f1c7e
Merge branch 'genericDefaults' of https://github.com/Microsoft/TypeSc…
rbuckton Jan 24, 2017
febde3f
Revert noConstraintType name change
rbuckton Jan 24, 2017
b58ef9e
Merge branch 'master' into genericDefaults
rbuckton Jan 30, 2017
7616e37
Use length() throught checker
rbuckton Jan 30, 2017
e001258
Move non-local type parameter check to resolveName
rbuckton Jan 30, 2017
9ba2a6b
Skip type parameters.
rbuckton Feb 1, 2017
6091050
Remove pre-computation of minTypeArgumentCount
rbuckton Feb 3, 2017
6ffcbf5
Merge branch 'master' into genericDefaults
rbuckton Feb 3, 2017
5bb2fe0
Simplify checkTypeParameterListsIdentical
rbuckton Feb 4, 2017
96181c0
Shortcut for class/namespace merge
rbuckton Feb 4, 2017
23216f9
Merge branch 'master' into genericDefaults
rbuckton Feb 15, 2017
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
429 changes: 349 additions & 80 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,23 @@ namespace ts {
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError);
}
}
if (node.default && !isPrivateMethodTypeParameter(node)) {
write(" = ");
if (node.parent.kind === SyntaxKind.FunctionType ||
node.parent.kind === SyntaxKind.ConstructorType ||
(node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral)) {
Debug.assert(node.parent.kind === SyntaxKind.MethodDeclaration ||
node.parent.kind === SyntaxKind.MethodSignature ||
node.parent.kind === SyntaxKind.FunctionType ||
node.parent.kind === SyntaxKind.ConstructorType ||
node.parent.kind === SyntaxKind.CallSignature ||
node.parent.kind === SyntaxKind.ConstructSignature);
emitType(node.default);
}
else {
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.default, getTypeParameterConstraintVisibilityError);
}
}

function getTypeParameterConstraintVisibilityError(): SymbolAccessibilityDiagnostic {
// Type parameter constraints are named by user so we should always be able to name it
Expand Down
12 changes: 12 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,18 @@
"category": "Error",
"code": 2704
},
"Required type parameters may not follow optional type parameters.": {
"category": "Error",
"code": 2705
},
"Type parameter '{0}' has a circular default.": {
"category": "Error",
"code": 2706
},
"Generic type '{0}' requires between {1} and {2} type arguments.": {
"category": "Error",
"code": 2707
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ namespace ts {
case SyntaxKind.TypeParameter:
return visitNode(cbNode, (<TypeParameterDeclaration>node).name) ||
visitNode(cbNode, (<TypeParameterDeclaration>node).constraint) ||
visitNode(cbNode, (<TypeParameterDeclaration>node).default) ||
visitNode(cbNode, (<TypeParameterDeclaration>node).expression);
case SyntaxKind.ShorthandPropertyAssignment:
return visitNodes(cbNodes, node.decorators) ||
Expand Down Expand Up @@ -2098,6 +2099,10 @@ namespace ts {
}
}

if (parseOptional(SyntaxKind.EqualsToken)) {
node.default = parseType();
}
Copy link
Member

@DanielRosenwasser DanielRosenwasser Jan 23, 2017

Choose a reason for hiding this comment

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

Nit: I would really like for if the parsing was order-agnostic for the purpose of error reporting, and then gave a grammar error later on. This could be done as a separate pass.


return finishNode(node);
}

Expand Down
12 changes: 12 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ namespace ts {
kind: SyntaxKind.TypeParameter;
name: Identifier;
constraint?: TypeNode;
default?: TypeNode;

// For error recovery purposes.
expression?: Expression;
Expand Down Expand Up @@ -2679,6 +2680,7 @@ namespace ts {
type?: Type; // Type of value symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
minTypeArgumentCount?: number;
inferredClassType?: Type; // Type of an inferred ES5 class
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
Expand Down Expand Up @@ -2880,6 +2882,8 @@ namespace ts {
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
localTypeParameters: TypeParameter[]; // Local type parameters (undefined if none)
/* @internal */
minTypeArgumentCount: number;
thisType: TypeParameter; // The "this" type (undefined if none)
/* @internal */
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
Expand Down Expand Up @@ -2986,18 +2990,23 @@ namespace ts {
/* @internal */
resolvedBaseConstraint: Type;
/* @internal */
resolvedDefault: Type;
/* @internal */
resolvedIndexType: IndexType;
}

// Type parameters (TypeFlags.TypeParameter)
export interface TypeParameter extends TypeVariable {
constraint: Type; // Constraint
default?: Type;
/* @internal */
target?: TypeParameter; // Instantiation target
/* @internal */
mapper?: TypeMapper; // Instantiation mapper
/* @internal */
isThisType?: boolean;
/* @internal */
resolvedDefaultType?: Type;
}

// Indexed access types (TypeFlags.IndexedAccess)
Expand All @@ -3021,6 +3030,8 @@ namespace ts {
export interface Signature {
declaration: SignatureDeclaration; // Originating declaration
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
/* @internal */
minTypeArgumentCount: number; // Number of non-optional type parameters
parameters: Symbol[]; // Parameters
/* @internal */
thisParameter?: Symbol; // symbol of this-type parameter
Expand Down Expand Up @@ -3084,6 +3095,7 @@ namespace ts {
inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType)
inferences: TypeInferences[]; // Inferences made for each type parameter
inferredTypes: Type[]; // Inferred type for each type parameter
suppliedTypes?: Type[]; // Supplied types for non-default type parameters
mapper?: TypeMapper; // Type mapper for this inference context
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
// It is optional because in contextual signature instantiation, nothing fails
Expand Down
14 changes: 14 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ namespace ts {
return undefined;
}

export function findDeclaration<T extends Declaration>(symbol: Symbol, predicate: (node: Declaration) => node is T): T | undefined;
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined;
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined {
const declarations = symbol.declarations;
if (declarations) {
for (const declaration of declarations) {
if (predicate(declaration)) {
return declaration;
}
}
}
return undefined;
}

export interface StringSymbolWriter extends SymbolWriter {
string(): string;
}
Expand Down
35 changes: 2 additions & 33 deletions src/lib/es2015.promise.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,14 @@ interface Promise<T> {
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then(onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<TResult>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;

/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}

interface PromiseConstructor {
Expand Down
34 changes: 1 addition & 33 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1316,39 +1316,7 @@ interface PromiseLike<T> {
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then(
onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null,
onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): PromiseLike<T>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(
onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null,
onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<T | TResult>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(
onfulfilled: (value: T) => TResult | PromiseLike<TResult>,
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): PromiseLike<TResult>;

/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(
onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>,
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
}

interface ArrayLike<T> {
Expand Down
1 change: 1 addition & 0 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ namespace ts {
parameters: Symbol[];
thisParameter: Symbol;
resolvedReturnType: Type;
minTypeArgumentCount: number;
minArgumentCount: number;
hasRestParameter: boolean;
hasLiteralTypes: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(10,23): error TS1055: Type 'typeof Thenable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
Types of property 'then' are incompatible.
Type '() => void' is not assignable to type '{ (onfulfilled?: (value: any) => any, onrejected?: (reason: any) => any): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => any, onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult1, TResult2>(onfulfilled: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>; }'.
Type '() => void' is not assignable to type '<TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<TResult1 | TResult2>'.
Type 'void' is not assignable to type 'PromiseLike<any>'.
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(17,16): error TS1059: Return expression in async function does not have a valid callable 'then' member.
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(23,25): error TS1058: Operand for 'await' does not have a valid callable 'then' member.
Expand Down Expand Up @@ -37,7 +37,7 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1
!!! error TS1055: Type 'typeof Thenable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
!!! error TS1055: Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
!!! error TS1055: Types of property 'then' are incompatible.
!!! error TS1055: Type '() => void' is not assignable to type '{ (onfulfilled?: (value: any) => any, onrejected?: (reason: any) => any): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => any, onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult1, TResult2>(onfulfilled: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>; }'.
!!! error TS1055: Type '() => void' is not assignable to type '<TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<TResult1 | TResult2>'.
!!! error TS1055: Type 'void' is not assignable to type 'PromiseLike<any>'.
async function fn7() { return; } // valid: Promise<void>
async function fn8() { return 1; } // valid: Promise<number>
Expand Down
Loading