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

Control flow based type analysis #8010

Merged
merged 70 commits into from
Apr 22, 2016
Merged
Changes from 1 commit
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
e67d15a
Initial implementation of control flow based type analysis
ahejlsberg Mar 22, 2016
afa1714
Add type annotations to suppress circularity errors
ahejlsberg Mar 22, 2016
7c45c7b
Fixing tests
ahejlsberg Mar 22, 2016
80c2e5e
Accepting new baselines
ahejlsberg Mar 22, 2016
33985b2
Adding a few optimizations
ahejlsberg Mar 24, 2016
ed5002c
Handle assignment of union types in getAssignmentReducedType
ahejlsberg Mar 25, 2016
6d25a42
Remove incorrect type predicate (could be true even when result is fa…
ahejlsberg Mar 25, 2016
bf78470
Fix overly aggressive optimization
ahejlsberg Mar 25, 2016
4f936c4
Add control flow tests
ivogabe Mar 25, 2016
7f02357
Merge pull request #7690 from ivogabe/controlFlowTypesTest
ahejlsberg Mar 25, 2016
9e965d4
Fix issues in analysis of do..while and for..in/for..of
ahejlsberg Mar 26, 2016
9de0a5d
Fix comment in test
ahejlsberg Mar 26, 2016
560bc3f
Accepting new baselines
ahejlsberg Mar 26, 2016
0820249
Fixing some tests
ahejlsberg Mar 26, 2016
5a5d89a
Accepting new baselines
ahejlsberg Mar 26, 2016
424074b
Use type {} for vacuous type guards / New getTypeWithFacts function
ahejlsberg Mar 30, 2016
c6f4de3
Remove unnecessary cast
ahejlsberg Mar 30, 2016
e53f390
Fix some tests
ahejlsberg Mar 30, 2016
a38d863
Accepting new baselines
ahejlsberg Mar 30, 2016
3d0fa31
Delete removeNullableKind, use getTypeWithFacts instead
ahejlsberg Mar 30, 2016
ce81ba5
Support unknown types (host object names) in typeof type guards
ahejlsberg Mar 31, 2016
354fd10
Separate error messages for 'null', 'undefined', or both.
ahejlsberg Apr 1, 2016
5179dd6
Flow analysis of &&, ||, and destructuring assignments
ahejlsberg Apr 8, 2016
019f5bd
Accepting new baselines
ahejlsberg Apr 8, 2016
f13c92f
Handle shorthand property assignments
ahejlsberg Apr 8, 2016
b03d087
Accepting new baselines
ahejlsberg Apr 8, 2016
7a32129
Support destructuring declarations in control flow analysis
ahejlsberg Apr 9, 2016
6fb9424
Accepting new baselines
ahejlsberg Apr 9, 2016
e45bac8
Adding test
ahejlsberg Apr 10, 2016
7dfcad6
Fixing fourslash tests
ahejlsberg Apr 10, 2016
92df029
Fixing tests
ahejlsberg Apr 10, 2016
32e6464
Accepting new baselines
ahejlsberg Apr 10, 2016
560e768
Fix linting errors
ahejlsberg Apr 10, 2016
b1e9f43
Merge branch 'master' into controlFlowTypes
ahejlsberg Apr 10, 2016
4c250d0
Accepting new baselines
ahejlsberg Apr 10, 2016
7c7a1c0
A few cosmetic changes
ahejlsberg Apr 12, 2016
df62fa0
Merge branch 'master' into controlFlowTypes
ahejlsberg Apr 12, 2016
586ac55
Fix finishFlow function and rename to finishFlowLabel
ahejlsberg Apr 12, 2016
cd88f1e
Adding regression test
ahejlsberg Apr 12, 2016
472ab7c
Accepting new baselines
ahejlsberg Apr 12, 2016
b689c07
Improving error reporting as suggested in code review
ahejlsberg Apr 13, 2016
1ed9871
Fix typo
ahejlsberg Apr 13, 2016
921efec
Improved handing of evolving types in iteration statements
ahejlsberg Apr 16, 2016
9aea708
Adding tests
ahejlsberg Apr 16, 2016
10889a0
Accepting new baselines
ahejlsberg Apr 16, 2016
2595f04
Removing unused properties
ahejlsberg Apr 17, 2016
b83dc88
Improve expression type caching to ensure consistent results
ahejlsberg Apr 18, 2016
538e22a
Adding tests
ahejlsberg Apr 18, 2016
b5104cb
Accepting new baselines
ahejlsberg Apr 18, 2016
87f55fa
Only evaluate assigned type when declared type is a union type
ahejlsberg Apr 18, 2016
9defdde
Accepting new baselines
ahejlsberg Apr 18, 2016
d28a4fe
typeof x === "function" type guards include Function interface
ahejlsberg Apr 18, 2016
d735b7a
Variables from different source files default to their declared type
ahejlsberg Apr 19, 2016
c8bf6d8
Variables from different module declarations default to their declare…
ahejlsberg Apr 19, 2016
ea96dfd
Support comma operator in type guards
ahejlsberg Apr 20, 2016
33e359f
Adding test
ahejlsberg Apr 20, 2016
bab8ef4
Accepting new baselines
ahejlsberg Apr 20, 2016
e9a7d3d
Removing unused logic
ahejlsberg Apr 20, 2016
a0101c0
Improve consistency of instanceof and user defined type guards
ahejlsberg Apr 21, 2016
729dfce
Fix incorrect user defined type guard function in compiler
ahejlsberg Apr 21, 2016
3045cf5
Add regression test
ahejlsberg Apr 21, 2016
06928b6
Accepting new baselines
ahejlsberg Apr 21, 2016
8a0bc3b
Support assignments in truthiness type guards
ahejlsberg Apr 21, 2016
d2b89be
Adding test
ahejlsberg Apr 21, 2016
ab4b039
Removing unused logic
ahejlsberg Apr 21, 2016
e12b2a7
Correct issue with exported variables in code flow analysis
ahejlsberg Apr 21, 2016
4fb31ac
Update fourslash test
ahejlsberg Apr 21, 2016
f06d3f6
Only narrow to {} in getNarrowedType when types are completely unrelated
ahejlsberg Apr 22, 2016
42e3fc4
Revert previous change
ahejlsberg Apr 22, 2016
0dee5ad
Accepting new baselines
ahejlsberg Apr 22, 2016
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
Prev Previous commit
Next Next commit
Improve consistency of instanceof and user defined type guards
  • Loading branch information
ahejlsberg committed Apr 21, 2016
commit a0101c0787e027725cd3224e71de5177368b556a
59 changes: 35 additions & 24 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7339,6 +7339,18 @@ namespace ts {
return false;
}

function typeMaybeSubtypeOf(source: Type, target: Type) {
if (!(source.flags & TypeFlags.Union)) {
return isTypeSubtypeOf(source, target);
}
for (const t of (<UnionType>source).types) {
if (isTypeSubtypeOf(t, target)) {
return true;
}
}
return false;
}

// Remove those constituent types of declaredType to which no constituent type of assignedType is assignable.
// For example, when a variable of type number | string | boolean is assigned a value of type number | boolean,
// we remove type string.
Expand Down Expand Up @@ -7766,30 +7778,29 @@ namespace ts {
return type;
}

function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type, assumeTrue: boolean) {
if (!assumeTrue) {
if (originalType.flags & TypeFlags.Union) {
return getUnionType(filter((<UnionType>originalType).types, t => !isTypeSubtypeOf(t, narrowedTypeCandidate)));
}
return originalType;
}

// If the current type is a union type, remove all constituents that aren't assignable to target. If that produces
// 0 candidates, fall back to the assignability check
if (originalType.flags & TypeFlags.Union) {
const assignableConstituents = filter((<UnionType>originalType).types, t => isTypeAssignableTo(t, narrowedTypeCandidate));
if (assignableConstituents.length) {
return getUnionType(assignableConstituents);
}
}

const targetType = originalType.flags & TypeFlags.TypeParameter ? getApparentType(originalType) : originalType;
if (isTypeAssignableTo(narrowedTypeCandidate, targetType)) {
// Narrow to the target type if it's assignable to the current type
return narrowedTypeCandidate;
}

return originalType;
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) {
if (typeMaybeSubtypeOf(type, candidate)) {
// If the current type, or a constituent of the current type, is a subtype of
// the candidate type then the current type contains the most specific information.
// and we simply filter out constituents that aren't applicable. For example,
// if the current type is string | string[] and the candidate type is any[],
// we filter out string.
return type.flags & TypeFlags.Union ?
getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, candidate) === assumeTrue)) :
assumeTrue ? type : emptyUnionType;
}
if (assumeTrue) {
// In the true branch of the remaining cases, if the candidate type is assignable
// to the current type, then we narrow to the candidate type. Otherwise, we narrow
// to an empty type (because we now know the types are completely unrelated). For
// example, if the current type is Object and the candidate type is string[], we
// narrow to string[]. But if the current type is string and the candidate is
// string[], we narrow to the empty type.
const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
return isTypeAssignableTo(candidate, targetType) ? candidate : emptyUnionType;
}
// In the false branch of the remaining cases we leave the type unchanged.
return type;
}

function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
Expand Down