Skip to content

Detect circularities when removing 'undefined' from defaulted params #37023

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

Merged
merged 1 commit into from
Feb 26, 2020
Merged
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
20 changes: 14 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20515,12 +20515,20 @@ namespace ts {

/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
const annotationIncludesUndefined = strictNullChecks &&
declaration.kind === SyntaxKind.Parameter &&
declaration.initializer &&
getFalsyFlags(declaredType) & TypeFlags.Undefined &&
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
if (pushTypeResolution(declaration.symbol, TypeSystemPropertyName.DeclaredType)) {
const annotationIncludesUndefined = strictNullChecks &&
declaration.kind === SyntaxKind.Parameter &&
declaration.initializer &&
getFalsyFlags(declaredType) & TypeFlags.Undefined &&
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
popTypeResolution();

return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
}
else {
reportCircularityError(declaration.symbol);
return declaredType;
}
}

function isConstraintPosition(node: Node) {
Expand Down
32 changes: 32 additions & 0 deletions tests/baselines/reference/circularOptionalityRemoval.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
tests/cases/compiler/circularOptionalityRemoval.ts(2,14): error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
tests/cases/compiler/circularOptionalityRemoval.ts(2,38): error TS2372: Parameter 'x' cannot be referenced in its initializer.
tests/cases/compiler/circularOptionalityRemoval.ts(2,38): error TS2532: Object is possibly 'undefined'.
tests/cases/compiler/circularOptionalityRemoval.ts(2,46): error TS2372: Parameter 'x' cannot be referenced in its initializer.
tests/cases/compiler/circularOptionalityRemoval.ts(5,14): error TS1015: Parameter cannot have question mark and initializer.
tests/cases/compiler/circularOptionalityRemoval.ts(5,14): error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
tests/cases/compiler/circularOptionalityRemoval.ts(5,27): error TS2304: Cannot find name 'someCondition'.
tests/cases/compiler/circularOptionalityRemoval.ts(5,54): error TS2372: Parameter 'x' cannot be referenced in its initializer.


==== tests/cases/compiler/circularOptionalityRemoval.ts (8 errors) ====
// Constructed repro
function fn1(x: number | undefined = x > 0 ? x : 0) { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
~
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.
~
!!! error TS2532: Object is possibly 'undefined'.
~
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.

// Report from user
function fn2(x?: string = someCondition ? 'value1' : x) { }
~
!!! error TS1015: Parameter cannot have question mark and initializer.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
~~~~~~~~~~~~~
!!! error TS2304: Cannot find name 'someCondition'.
~
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.
16 changes: 16 additions & 0 deletions tests/baselines/reference/circularOptionalityRemoval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [circularOptionalityRemoval.ts]
// Constructed repro
function fn1(x: number | undefined = x > 0 ? x : 0) { }

// Report from user
function fn2(x?: string = someCondition ? 'value1' : x) { }

//// [circularOptionalityRemoval.js]
// Constructed repro
function fn1(x) {
if (x === void 0) { x = x > 0 ? x : 0; }
}
// Report from user
function fn2(x) {
if (x === void 0) { x = someCondition ? 'value1' : x; }
}
14 changes: 14 additions & 0 deletions tests/baselines/reference/circularOptionalityRemoval.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
=== tests/cases/compiler/circularOptionalityRemoval.ts ===
// Constructed repro
function fn1(x: number | undefined = x > 0 ? x : 0) { }
>fn1 : Symbol(fn1, Decl(circularOptionalityRemoval.ts, 0, 0))
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))

// Report from user
function fn2(x?: string = someCondition ? 'value1' : x) { }
>fn2 : Symbol(fn2, Decl(circularOptionalityRemoval.ts, 1, 55))
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 4, 13))
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 4, 13))

21 changes: 21 additions & 0 deletions tests/baselines/reference/circularOptionalityRemoval.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
=== tests/cases/compiler/circularOptionalityRemoval.ts ===
// Constructed repro
function fn1(x: number | undefined = x > 0 ? x : 0) { }
>fn1 : (x?: number | undefined) => void
>x : number | undefined
>x > 0 ? x : 0 : number | undefined
>x > 0 : boolean
>x : number | undefined
>0 : 0
>x : number | undefined
>0 : 0

// Report from user
function fn2(x?: string = someCondition ? 'value1' : x) { }
>fn2 : (x?: string | undefined) => void
>x : string | undefined
>someCondition ? 'value1' : x : string | undefined
>someCondition : any
>'value1' : "value1"
>x : string | undefined

7 changes: 7 additions & 0 deletions tests/cases/compiler/circularOptionalityRemoval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @strictNullChecks: true

// Constructed repro
function fn1(x: number | undefined = x > 0 ? x : 0) { }

// Report from user
function fn2(x?: string = someCondition ? 'value1' : x) { }