Merge remote-tracking branch 'origin/master' into usePromise

This commit is contained in:
Mohamed Hegazy 2017-02-13 15:15:24 -08:00
commit 143edff303
24 changed files with 863 additions and 17 deletions

View file

@ -1045,7 +1045,35 @@ namespace ts {
if (node.finallyBlock) {
// in finally flow is combined from pre-try/flow from try/flow from catch
// pre-flow is necessary to make sure that finally is reachable even if finally flows in both try and finally blocks are unreachable
addAntecedent(preFinallyLabel, preTryFlow);
// also for finally blocks we inject two extra edges into the flow graph.
// first -> edge that connects pre-try flow with the label at the beginning of the finally block, it has lock associated with it
// second -> edge that represents post-finally flow.
// these edges are used in following scenario:
// let a; (1)
// try { a = someOperation(); (2)}
// finally { (3) console.log(a) } (4)
// (5) a
// flow graph for this case looks roughly like this (arrows show ):
// (1-pre-try-flow) <--.. <-- (2-post-try-flow)
// ^ ^
// |*****(3-pre-finally-label) -----|
// ^
// |-- ... <-- (4-post-finally-label) <--- (5)
// In case when we walk the flow starting from inside the finally block we want to take edge '*****' into account
// since it ensures that finally is always reachable. However when we start outside the finally block and go through label (5)
// then edge '*****' should be discarded because label 4 is only reachable if post-finally label-4 is reachable
// Simply speaking code inside finally block is treated as reachable as pre-try-flow
// since we conservatively assume that any line in try block can throw or return in which case we'll enter finally.
// However code after finally is reachable only if control flow was not abrupted in try/catch or finally blocks - it should be composed from
// final flows of these blocks without taking pre-try flow into account.
//
// extra edges that we inject allows to control this behavior
// if when walking the flow we step on post-finally edge - we can mark matching pre-finally edge as locked so it will be skipped.
const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preTryFlow, lock: {} };
addAntecedent(preFinallyLabel, preFinallyFlow);
currentFlow = finishFlowLabel(preFinallyLabel);
bind(node.finallyBlock);
// if flow after finally is unreachable - keep it
@ -1061,6 +1089,11 @@ namespace ts {
: unreachableFlow;
}
}
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
const afterFinallyFlow: AfterFinallyFlow = { flags: FlowFlags.AfterFinally, antecedent: currentFlow };
preFinallyFlow.lock = afterFinallyFlow;
currentFlow = afterFinallyFlow;
}
}
else {
currentFlow = finishFlowLabel(preFinallyLabel);

View file

@ -2690,7 +2690,11 @@ namespace ts {
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack);
let type = getTypeOfSymbol(p);
if (isRequiredInitializedParameter(parameterNode)) {
type = includeFalsyTypes(type, TypeFlags.Undefined);
}
buildTypeDisplay(type, writer, enclosingDeclaration, flags, symbolStack);
}
function buildBindingPatternDisplay(bindingPattern: BindingPattern, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
@ -3271,6 +3275,16 @@ namespace ts {
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
}
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
function removeOptionalityFromAnnotation(annotatedType: Type, declaration: VariableLikeDeclaration): Type {
const annotationIncludesUndefined = strictNullChecks &&
declaration.kind === SyntaxKind.Parameter &&
declaration.initializer &&
getFalsyFlags(annotatedType) & TypeFlags.Undefined &&
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
return annotationIncludesUndefined ? getNonNullableType(annotatedType) : annotatedType;
}
// Return the inferred type for a variable, parameter, or property declaration
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
if (declaration.flags & NodeFlags.JavaScriptFile) {
@ -3304,7 +3318,8 @@ namespace ts {
// Use type from type annotation if one is present
if (declaration.type) {
return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality);
const declaredType = removeOptionalityFromAnnotation(getTypeFromTypeNode(declaration.type), declaration);
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
}
if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) &&
@ -5198,6 +5213,12 @@ namespace ts {
Debug.assert(parameterIndex >= 0);
return parameterIndex >= signature.minArgumentCount;
}
const iife = getImmediatelyInvokedFunctionExpression(node.parent);
if (iife) {
return !node.type &&
!node.dotDotDotToken &&
indexOf((node.parent as SignatureDeclaration).parameters, node) >= iife.arguments.length;
}
return false;
}
@ -7762,16 +7783,36 @@ namespace ts {
if (target.flags & TypeFlags.Union && containsType(targetTypes, source)) {
return Ternary.True;
}
const len = targetTypes.length;
for (let i = 0; i < len; i++) {
const related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1);
for (const type of targetTypes) {
const related = isRelatedTo(source, type, /*reportErrors*/ false);
if (related) {
return related;
}
}
if (reportErrors) {
const discriminantType = findMatchingDiscriminantType(source, target);
isRelatedTo(source, discriminantType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true);
}
return Ternary.False;
}
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
const sourceProperties = getPropertiesOfObjectType(source);
if (sourceProperties) {
for (const sourceProperty of sourceProperties) {
if (isDiscriminantProperty(target, sourceProperty.name)) {
const sourceType = getTypeOfSymbol(sourceProperty);
for (const type of target.types) {
const targetType = getTypeOfPropertyOfType(type, sourceProperty.name);
if (targetType && isRelatedTo(sourceType, targetType)) {
return type;
}
}
}
}
}
}
function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
let result = Ternary.True;
const targetTypes = target.types;
@ -8592,7 +8633,7 @@ namespace ts {
if (flags & TypeFlags.Void) types.push(voidType);
if (flags & TypeFlags.Undefined) types.push(undefinedType);
if (flags & TypeFlags.Null) types.push(nullType);
return getUnionType(types, /*subtypeReduction*/ true);
return getUnionType(types);
}
function removeDefinitelyFalsyTypes(type: Type): Type {
@ -9875,7 +9916,19 @@ namespace ts {
}
}
let type: FlowType;
if (flow.flags & FlowFlags.Assignment) {
if (flow.flags & FlowFlags.AfterFinally) {
// block flow edge: finally -> pre-try (for larger explanation check comment in binder.ts - bindTryStatement
(<AfterFinallyFlow>flow).locked = true;
type = getTypeAtFlowNode((<AfterFinallyFlow>flow).antecedent);
(<AfterFinallyFlow>flow).locked = false;
}
else if (flow.flags & FlowFlags.PreFinally) {
// locked pre-finally flows are filtered out in getTypeAtFlowBranchLabel
// so here just redirect to antecedent
flow = (<PreFinallyFlow>flow).antecedent;
continue;
}
else if (flow.flags & FlowFlags.Assignment) {
type = getTypeAtFlowAssignment(<FlowAssignment>flow);
if (!type) {
flow = (<FlowAssignment>flow).antecedent;
@ -10031,6 +10084,12 @@ namespace ts {
let subtypeReduction = false;
let seenIncomplete = false;
for (const antecedent of flow.antecedents) {
if (antecedent.flags & FlowFlags.PreFinally && (<PreFinallyFlow>antecedent).lock.locked) {
// if flow correspond to branch from pre-try to finally and this branch is locked - this means that
// we initially have started following the flow outside the finally block.
// in this case we should ignore this branch.
continue;
}
const flowType = getTypeAtFlowNode(antecedent);
const type = getTypeFromFlowType(flowType);
// If the type at a particular antecedent path is the declared type and the
@ -20710,6 +20769,13 @@ namespace ts {
return false;
}
function isRequiredInitializedParameter(parameter: ParameterDeclaration) {
return strictNullChecks &&
!isOptionalParameter(parameter) &&
parameter.initializer &&
!(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier);
}
function getNodeCheckFlags(node: Node): NodeCheckFlags {
node = getParseTreeNode(node);
return node ? getNodeLinks(node).flags : undefined;
@ -20801,10 +20867,12 @@ namespace ts {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) {
// Get type of the symbol if this is the valid symbol otherwise get type at location
const symbol = getSymbolOfNode(declaration);
const type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
? getWidenedLiteralType(getTypeOfSymbol(symbol))
: unknownType;
if (flags & TypeFormatFlags.AddUndefined) {
type = includeFalsyTypes(type, TypeFlags.Undefined);
}
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
}
@ -20903,6 +20971,7 @@ namespace ts {
isTopLevelValueImportEqualsWithEntityName,
isDeclarationVisible,
isImplementationOfOverload,
isRequiredInitializedParameter,
writeTypeOfDeclaration,
writeReturnTypeOfSignatureDeclaration,
writeTypeOfExpression,

View file

@ -324,13 +324,20 @@ namespace ts {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (type) {
// use the checker's type, not the declared type,
// for non-optional initialized parameters that aren't a parameter property
const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter &&
resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration);
if (type && !shouldUseResolverType) {
// Write the type
emitType(type);
}
else {
errorNameNode = declaration.name;
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer);
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue |
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
errorNameNode = undefined;
}
}

View file

@ -2071,10 +2071,25 @@
ArrayMutation = 1 << 8, // Potential array mutation
Referenced = 1 << 9, // Referenced as antecedent once
Shared = 1 << 10, // Referenced as antecedent more than once
PreFinally = 1 << 11, // Injected edge that links pre-finally label and pre-try flow
AfterFinally = 1 << 12, // Injected edge that links post-finally flow with the rest of the graph
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
}
export interface FlowLock {
locked?: boolean;
}
export interface AfterFinallyFlow extends FlowNode, FlowLock {
antecedent: FlowNode;
}
export interface PreFinallyFlow extends FlowNode {
antecedent: FlowNode;
lock: FlowLock;
}
export interface FlowNode {
flags: FlowFlags;
id?: number; // Node id used by flow type cache in checker
@ -2474,7 +2489,8 @@
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
InTypeAlias = 0x00000200, // Writing type in type alias declaration
UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
AddUndefined = 0x00001000, // Add undefined to types of initialized, non-optional parameters
}
export const enum SymbolFormatFlags {
@ -2579,6 +2595,7 @@
isDeclarationVisible(node: Declaration): boolean;
collectLinkedAliases(node: Identifier): Node[];
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;

View file

@ -253,8 +253,8 @@ let eleven = (o => o.a(11))({ a: function(n) { return n; } });
// missing arguments
(function(x, undefined) { return x; })(42);
>(function(x, undefined) { return x; })(42) : number
>(function(x, undefined) { return x; }) : (x: number, undefined: any) => number
>function(x, undefined) { return x; } : (x: number, undefined: any) => number
>(function(x, undefined) { return x; }) : (x: number, undefined?: any) => number
>function(x, undefined) { return x; } : (x: number, undefined?: any) => number
>x : number
>undefined : any
>x : number
@ -262,8 +262,8 @@ let eleven = (o => o.a(11))({ a: function(n) { return n; } });
((x, y, z) => 42)();
>((x, y, z) => 42)() : number
>((x, y, z) => 42) : (x: any, y: any, z: any) => number
>(x, y, z) => 42 : (x: any, y: any, z: any) => number
>((x, y, z) => 42) : (x?: any, y?: any, z?: any) => number
>(x, y, z) => 42 : (x?: any, y?: any, z?: any) => number
>x : any
>y : any
>z : any

View file

@ -0,0 +1,112 @@
//// [defaultParameterAddsUndefinedWithStrictNullChecks.ts]
function f(addUndefined1 = "J", addUndefined2?: number) {
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined = "J", addDefined: number) {
return addUndefined.length + addDefined;
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x: string = "string", b: number) {
x.length;
}
function foo2(x = "string", b: number) {
x.length; // ok, should be string
}
function foo3(x: string | undefined = "string", b: number) {
x.length; // ok, should be string
}
function foo4(x: string | undefined = undefined, b: number) {
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x = true) {
if (x === false) {
return x;
}
}
declare const cond: boolean;
function removeNothing(y = cond ? true : undefined) {
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}
//// [defaultParameterAddsUndefinedWithStrictNullChecks.js]
function f(addUndefined1, addUndefined2) {
if (addUndefined1 === void 0) { addUndefined1 = "J"; }
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined, addDefined) {
if (addUndefined === void 0) { addUndefined = "J"; }
return addUndefined.length + addDefined;
}
var total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x, b) {
if (x === void 0) { x = "string"; }
x.length;
}
function foo2(x, b) {
if (x === void 0) { x = "string"; }
x.length; // ok, should be string
}
function foo3(x, b) {
if (x === void 0) { x = "string"; }
x.length; // ok, should be string
}
function foo4(x, b) {
if (x === void 0) { x = undefined; }
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x) {
if (x === void 0) { x = true; }
if (x === false) {
return x;
}
}
function removeNothing(y) {
if (y === void 0) { y = cond ? true : undefined; }
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}
//// [defaultParameterAddsUndefinedWithStrictNullChecks.d.ts]
declare function f(addUndefined1?: string, addUndefined2?: number): number;
declare function g(addUndefined: string | undefined, addDefined: number): number;
declare let total: number;
declare function foo1(x: string | undefined, b: number): void;
declare function foo2(x: string | undefined, b: number): void;
declare function foo3(x: string | undefined, b: number): void;
declare function foo4(x: string | undefined, b: number): void;
declare function removeUndefinedButNotFalse(x?: boolean): false | undefined;
declare const cond: boolean;
declare function removeNothing(y?: boolean | undefined): boolean;

View file

@ -0,0 +1,135 @@
=== tests/cases/compiler/defaultParameterAddsUndefinedWithStrictNullChecks.ts ===
function f(addUndefined1 = "J", addUndefined2?: number) {
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>addUndefined1 : Symbol(addUndefined1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 11))
>addUndefined2 : Symbol(addUndefined2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 31))
return addUndefined1.length + (addUndefined2 || 0);
>addUndefined1.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined1 : Symbol(addUndefined1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 11))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined2 : Symbol(addUndefined2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 31))
}
function g(addUndefined = "J", addDefined: number) {
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>addUndefined : Symbol(addUndefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 11))
>addDefined : Symbol(addDefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 30))
return addUndefined.length + addDefined;
>addUndefined.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined : Symbol(addUndefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 11))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addDefined : Symbol(addDefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 30))
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
>total : Symbol(total, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 6, 3))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>undefined : Symbol(undefined)
total = g('c', 3) + g(undefined, 4);
>total : Symbol(total, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 6, 3))
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>undefined : Symbol(undefined)
function foo1(x: string = "string", b: number) {
>foo1 : Symbol(foo1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 7, 36))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 35))
x.length;
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo2(x = "string", b: number) {
>foo2 : Symbol(foo2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 11, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 27))
x.length; // ok, should be string
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo3(x: string | undefined = "string", b: number) {
>foo3 : Symbol(foo3, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 15, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 47))
x.length; // ok, should be string
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo4(x: string | undefined = undefined, b: number) {
>foo4 : Symbol(foo4, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 19, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 14))
>undefined : Symbol(undefined)
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 48))
x; // should be string | undefined
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 14))
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
>foo1 : Symbol(foo1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 7, 36))
>undefined : Symbol(undefined)
foo2(undefined, 1);
>foo2 : Symbol(foo2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 11, 1))
>undefined : Symbol(undefined)
foo3(undefined, 1);
>foo3 : Symbol(foo3, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 15, 1))
>undefined : Symbol(undefined)
foo4(undefined, 1);
>foo4 : Symbol(foo4, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 19, 1))
>undefined : Symbol(undefined)
function removeUndefinedButNotFalse(x = true) {
>removeUndefinedButNotFalse : Symbol(removeUndefinedButNotFalse, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 31, 19))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
if (x === false) {
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
return x;
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
}
}
declare const cond: boolean;
>cond : Symbol(cond, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 13))
function removeNothing(y = cond ? true : undefined) {
>removeNothing : Symbol(removeNothing, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 28))
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
>cond : Symbol(cond, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 13))
>undefined : Symbol(undefined)
if (y !== undefined) {
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
>undefined : Symbol(undefined)
if (y === false) {
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
return y;
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
}
}
return true;
}

View file

@ -0,0 +1,180 @@
=== tests/cases/compiler/defaultParameterAddsUndefinedWithStrictNullChecks.ts ===
function f(addUndefined1 = "J", addUndefined2?: number) {
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>addUndefined1 : string
>"J" : "J"
>addUndefined2 : number | undefined
return addUndefined1.length + (addUndefined2 || 0);
>addUndefined1.length + (addUndefined2 || 0) : number
>addUndefined1.length : number
>addUndefined1 : string
>length : number
>(addUndefined2 || 0) : number
>addUndefined2 || 0 : number
>addUndefined2 : number | undefined
>0 : 0
}
function g(addUndefined = "J", addDefined: number) {
>g : (addUndefined: string | undefined, addDefined: number) => number
>addUndefined : string
>"J" : "J"
>addDefined : number
return addUndefined.length + addDefined;
>addUndefined.length + addDefined : number
>addUndefined.length : number
>addUndefined : string
>length : number
>addDefined : number
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
>total : number
>f() + f('a', 1) + f('b') + f(undefined, 2) : number
>f() + f('a', 1) + f('b') : number
>f() + f('a', 1) : number
>f() : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>f('a', 1) : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>'a' : "a"
>1 : 1
>f('b') : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>'b' : "b"
>f(undefined, 2) : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>undefined : undefined
>2 : 2
total = g('c', 3) + g(undefined, 4);
>total = g('c', 3) + g(undefined, 4) : number
>total : number
>g('c', 3) + g(undefined, 4) : number
>g('c', 3) : number
>g : (addUndefined: string | undefined, addDefined: number) => number
>'c' : "c"
>3 : 3
>g(undefined, 4) : number
>g : (addUndefined: string | undefined, addDefined: number) => number
>undefined : undefined
>4 : 4
function foo1(x: string = "string", b: number) {
>foo1 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length;
>x.length : number
>x : string
>length : number
}
function foo2(x = "string", b: number) {
>foo2 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length; // ok, should be string
>x.length : number
>x : string
>length : number
}
function foo3(x: string | undefined = "string", b: number) {
>foo3 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length; // ok, should be string
>x.length : number
>x : string
>length : number
}
function foo4(x: string | undefined = undefined, b: number) {
>foo4 : (x: string | undefined, b: number) => void
>x : string | undefined
>undefined : undefined
>b : number
x; // should be string | undefined
>x : string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
>foo1(undefined, 1) : void
>foo1 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo2(undefined, 1);
>foo2(undefined, 1) : void
>foo2 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo3(undefined, 1);
>foo3(undefined, 1) : void
>foo3 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo4(undefined, 1);
>foo4(undefined, 1) : void
>foo4 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
function removeUndefinedButNotFalse(x = true) {
>removeUndefinedButNotFalse : (x?: boolean) => false | undefined
>x : boolean
>true : true
if (x === false) {
>x === false : boolean
>x : boolean
>false : false
return x;
>x : false
}
}
declare const cond: boolean;
>cond : boolean
function removeNothing(y = cond ? true : undefined) {
>removeNothing : (y?: boolean | undefined) => boolean
>y : boolean | undefined
>cond ? true : undefined : true | undefined
>cond : boolean
>true : true
>undefined : undefined
if (y !== undefined) {
>y !== undefined : boolean
>y : boolean | undefined
>undefined : undefined
if (y === false) {
>y === false : boolean
>y : boolean
>false : false
return y;
>y : false
}
}
return true;
>true : true
}

View file

@ -0,0 +1,23 @@
tests/cases/compiler/discriminatedUnionErrorMessage.ts(8,5): error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Shape'.
Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Square'.
Property 'size' is missing in type '{ kind: "sq"; x: number; y: number; }'.
==== tests/cases/compiler/discriminatedUnionErrorMessage.ts (1 errors) ====
type Square = { kind: "sq", size: number }
type Rectangle = { kind: "rt", x: number, y: number }
type Circle = { kind: "cr", radius: number }
type Shape =
| Square
| Rectangle
| Circle;
let shape: Shape = {
~~~~~
!!! error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Shape'.
!!! error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Square'.
!!! error TS2322: Property 'size' is missing in type '{ kind: "sq"; x: number; y: number; }'.
kind: "sq",
x: 12,
y: 13,
}

View file

@ -0,0 +1,21 @@
//// [discriminatedUnionErrorMessage.ts]
type Square = { kind: "sq", size: number }
type Rectangle = { kind: "rt", x: number, y: number }
type Circle = { kind: "cr", radius: number }
type Shape =
| Square
| Rectangle
| Circle;
let shape: Shape = {
kind: "sq",
x: 12,
y: 13,
}
//// [discriminatedUnionErrorMessage.js]
var shape = {
kind: "sq",
x: 12,
y: 13
};

View file

@ -0,0 +1,25 @@
//// [flowAfterFinally1.ts]
declare function openFile(): void
declare function closeFile(): void
declare function someOperation(): {}
var result: {}
openFile()
try {
result = someOperation()
} finally {
closeFile()
}
result // should not error here
//// [flowAfterFinally1.js]
var result;
openFile();
try {
result = someOperation();
}
finally {
closeFile();
}
result; // should not error here

View file

@ -0,0 +1,29 @@
=== tests/cases/compiler/flowAfterFinally1.ts ===
declare function openFile(): void
>openFile : Symbol(openFile, Decl(flowAfterFinally1.ts, 0, 0))
declare function closeFile(): void
>closeFile : Symbol(closeFile, Decl(flowAfterFinally1.ts, 0, 33))
declare function someOperation(): {}
>someOperation : Symbol(someOperation, Decl(flowAfterFinally1.ts, 1, 34))
var result: {}
>result : Symbol(result, Decl(flowAfterFinally1.ts, 4, 3))
openFile()
>openFile : Symbol(openFile, Decl(flowAfterFinally1.ts, 0, 0))
try {
result = someOperation()
>result : Symbol(result, Decl(flowAfterFinally1.ts, 4, 3))
>someOperation : Symbol(someOperation, Decl(flowAfterFinally1.ts, 1, 34))
} finally {
closeFile()
>closeFile : Symbol(closeFile, Decl(flowAfterFinally1.ts, 0, 33))
}
result // should not error here
>result : Symbol(result, Decl(flowAfterFinally1.ts, 4, 3))

View file

@ -0,0 +1,33 @@
=== tests/cases/compiler/flowAfterFinally1.ts ===
declare function openFile(): void
>openFile : () => void
declare function closeFile(): void
>closeFile : () => void
declare function someOperation(): {}
>someOperation : () => {}
var result: {}
>result : {}
openFile()
>openFile() : void
>openFile : () => void
try {
result = someOperation()
>result = someOperation() : {}
>result : {}
>someOperation() : {}
>someOperation : () => {}
} finally {
closeFile()
>closeFile() : void
>closeFile : () => void
}
result // should not error here
>result : {}

View file

@ -0,0 +1,14 @@
//// [optionalParameterRetainsNull.ts]
interface Bar { bar: number; foo: object | null; }
let a = {
test<K extends keyof Bar> (a: K, b?: Bar[K] | null) { }
};
a.test("bar", null); // ok, null is assignable to number | null | undefined
//// [optionalParameterRetainsNull.js]
var a = {
test: function (a, b) { }
};
a.test("bar", null); // ok, null is assignable to number | null | undefined

View file

@ -0,0 +1,25 @@
=== tests/cases/compiler/optionalParameterRetainsNull.ts ===
interface Bar { bar: number; foo: object | null; }
>Bar : Symbol(Bar, Decl(optionalParameterRetainsNull.ts, 0, 0))
>bar : Symbol(Bar.bar, Decl(optionalParameterRetainsNull.ts, 0, 15))
>foo : Symbol(Bar.foo, Decl(optionalParameterRetainsNull.ts, 0, 29))
let a = {
>a : Symbol(a, Decl(optionalParameterRetainsNull.ts, 2, 3))
test<K extends keyof Bar> (a: K, b?: Bar[K] | null) { }
>test : Symbol(test, Decl(optionalParameterRetainsNull.ts, 2, 9))
>K : Symbol(K, Decl(optionalParameterRetainsNull.ts, 3, 7))
>Bar : Symbol(Bar, Decl(optionalParameterRetainsNull.ts, 0, 0))
>a : Symbol(a, Decl(optionalParameterRetainsNull.ts, 3, 29))
>K : Symbol(K, Decl(optionalParameterRetainsNull.ts, 3, 7))
>b : Symbol(b, Decl(optionalParameterRetainsNull.ts, 3, 34))
>Bar : Symbol(Bar, Decl(optionalParameterRetainsNull.ts, 0, 0))
>K : Symbol(K, Decl(optionalParameterRetainsNull.ts, 3, 7))
};
a.test("bar", null); // ok, null is assignable to number | null | undefined
>a.test : Symbol(test, Decl(optionalParameterRetainsNull.ts, 2, 9))
>a : Symbol(a, Decl(optionalParameterRetainsNull.ts, 2, 3))
>test : Symbol(test, Decl(optionalParameterRetainsNull.ts, 2, 9))

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/optionalParameterRetainsNull.ts ===
interface Bar { bar: number; foo: object | null; }
>Bar : Bar
>bar : number
>foo : object | null
>null : null
let a = {
>a : { test<K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined): void; }
>{ test<K extends keyof Bar> (a: K, b?: Bar[K] | null) { }} : { test<K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined): void; }
test<K extends keyof Bar> (a: K, b?: Bar[K] | null) { }
>test : <K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined) => void
>K : K
>Bar : Bar
>a : K
>K : K
>b : Bar[K] | null | undefined
>Bar : Bar
>K : K
>null : null
};
a.test("bar", null); // ok, null is assignable to number | null | undefined
>a.test("bar", null) : void
>a.test : <K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined) => void
>a : { test<K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined): void; }
>test : <K extends "bar" | "foo">(a: K, b?: Bar[K] | null | undefined) => void
>"bar" : "bar"
>null : null

View file

@ -28,6 +28,7 @@ foo + bar + baz;
//// [a.js]
"use strict";
exports.__esModule = true;
var foo = require("foo");
var bar = require("bar");
var baz = require("baz");

View file

@ -16,3 +16,4 @@ import foo = require("foo");
//// [a.js]
"use strict";
exports.__esModule = true;

View file

@ -38,6 +38,7 @@ exports.__esModule = true;
exports.l = 2;
//// [index.js]
"use strict";
exports.__esModule = true;
exports.m = 3;
//// [a.js]
"use strict";

View file

@ -0,0 +1,51 @@
// @strictNullChecks: true
// @declaration: true
function f(addUndefined1 = "J", addUndefined2?: number) {
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined = "J", addDefined: number) {
return addUndefined.length + addDefined;
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x: string = "string", b: number) {
x.length;
}
function foo2(x = "string", b: number) {
x.length; // ok, should be string
}
function foo3(x: string | undefined = "string", b: number) {
x.length; // ok, should be string
}
function foo4(x: string | undefined = undefined, b: number) {
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x = true) {
if (x === false) {
return x;
}
}
declare const cond: boolean;
function removeNothing(y = cond ? true : undefined) {
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}

View file

@ -0,0 +1,12 @@
type Square = { kind: "sq", size: number }
type Rectangle = { kind: "rt", x: number, y: number }
type Circle = { kind: "cr", radius: number }
type Shape =
| Square
| Rectangle
| Circle;
let shape: Shape = {
kind: "sq",
x: 12,
y: 13,
}

View file

@ -0,0 +1,14 @@
// @strictNullChecks: true
declare function openFile(): void
declare function closeFile(): void
declare function someOperation(): {}
var result: {}
openFile()
try {
result = someOperation()
} finally {
closeFile()
}
result // should not error here

View file

@ -0,0 +1,7 @@
// @strictNullChecks: true
interface Bar { bar: number; foo: object | null; }
let a = {
test<K extends keyof Bar> (a: K, b?: Bar[K] | null) { }
};
a.test("bar", null); // ok, null is assignable to number | null | undefined

View file

@ -0,0 +1,5 @@
/// <reference path='fourslash.ts'/>
// @strictNullChecks: true
////var iife = (function foo/*1*/(x, y) { return x })(12);
verify.quickInfoAt('1', '(local function) foo(x: number, y?: undefined): number');