Skip to content

Commit 0c18d03

Browse files
committed
Merge branch 'master' into incrementalLateSymbol
2 parents d919f2c + b9145f9 commit 0c18d03

File tree

38 files changed

+1732
-72
lines changed

38 files changed

+1732
-72
lines changed

src/compiler/builder.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,7 @@ namespace ts {
236236
}
237237
});
238238

239-
if (oldCompilerOptions &&
240-
(oldCompilerOptions.outDir !== compilerOptions.outDir ||
241-
oldCompilerOptions.declarationDir !== compilerOptions.declarationDir ||
242-
(oldCompilerOptions.outFile || oldCompilerOptions.out) !== (compilerOptions.outFile || compilerOptions.out))) {
239+
if (oldCompilerOptions && compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions)) {
243240
// Add all files to affectedFilesPendingEmit since emit changed
244241
state.affectedFilesPendingEmit = concatenate(state.affectedFilesPendingEmit, newProgram.getSourceFiles().map(f => f.path));
245242
if (state.affectedFilesPendingEmitIndex === undefined) {

src/compiler/checker.ts

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ namespace ts {
114114
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
115115
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
116116
getTypeCount: () => typeCount,
117+
getRelationCacheSizes: () => ({
118+
assignable: assignableRelation.size,
119+
identity: identityRelation.size,
120+
subtype: subtypeRelation.size,
121+
}),
117122
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
118123
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
119124
isUnknownSymbol: symbol => symbol === unknownSymbol,
@@ -7474,6 +7479,25 @@ namespace ts {
74747479
return type.resolvedProperties;
74757480
}
74767481

7482+
function getPossiblePropertiesOfUnionType(type: UnionType): Symbol[] {
7483+
if (type.possiblePropertyCache) {
7484+
return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray;
7485+
}
7486+
type.possiblePropertyCache = createSymbolTable();
7487+
for (const t of type.types) {
7488+
for (const p of getPropertiesOfType(t)) {
7489+
if (!type.possiblePropertyCache.has(p.escapedName)) {
7490+
const prop = getUnionOrIntersectionProperty(type, p.escapedName);
7491+
if (prop) {
7492+
type.possiblePropertyCache.set(p.escapedName, prop);
7493+
}
7494+
}
7495+
}
7496+
}
7497+
// We can't simply use the normal property cache here, since that will contain cached apparent type members :(
7498+
return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray;
7499+
}
7500+
74777501
function getPropertiesOfType(type: Type): Symbol[] {
74787502
type = getApparentType(type);
74797503
return type.flags & TypeFlags.UnionOrIntersection ?
@@ -7831,7 +7855,7 @@ namespace ts {
78317855
const isUnion = containingType.flags & TypeFlags.Union;
78327856
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
78337857
// Flags we want to propagate to the result if they exist in all source symbols
7834-
let commonFlags = isUnion ? SymbolFlags.None : SymbolFlags.Optional;
7858+
let optionalFlag = isUnion ? SymbolFlags.None : SymbolFlags.Optional;
78357859
let syntheticFlag = CheckFlags.SyntheticMethod;
78367860
let checkFlags = 0;
78377861
for (const current of containingType.types) {
@@ -7840,7 +7864,12 @@ namespace ts {
78407864
const prop = getPropertyOfType(type, name);
78417865
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
78427866
if (prop && !(modifiers & excludeModifiers)) {
7843-
commonFlags &= prop.flags;
7867+
if (isUnion) {
7868+
optionalFlag |= (prop.flags & SymbolFlags.Optional);
7869+
}
7870+
else {
7871+
optionalFlag &= prop.flags;
7872+
}
78447873
const id = "" + getSymbolId(prop);
78457874
if (!propSet.has(id)) {
78467875
propSet.set(id, prop);
@@ -7858,10 +7887,11 @@ namespace ts {
78587887
const indexInfo = !isLateBoundName(name) && (isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number) || getIndexInfoOfType(type, IndexKind.String));
78597888
if (indexInfo) {
78607889
checkFlags |= indexInfo.isReadonly ? CheckFlags.Readonly : 0;
7890+
checkFlags |= CheckFlags.WritePartial;
78617891
indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type);
78627892
}
78637893
else {
7864-
checkFlags |= CheckFlags.Partial;
7894+
checkFlags |= CheckFlags.ReadPartial;
78657895
}
78667896
}
78677897
}
@@ -7870,7 +7900,7 @@ namespace ts {
78707900
return undefined;
78717901
}
78727902
const props = arrayFrom(propSet.values());
7873-
if (props.length === 1 && !(checkFlags & CheckFlags.Partial) && !indexTypes) {
7903+
if (props.length === 1 && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) {
78747904
return props[0];
78757905
}
78767906
let declarations: Declaration[] | undefined;
@@ -7901,7 +7931,7 @@ namespace ts {
79017931
propTypes.push(type);
79027932
}
79037933
addRange(propTypes, indexTypes);
7904-
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
7934+
const result = createSymbol(SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags);
79057935
result.containingType = containingType;
79067936
if (!hasNonUniformValueDeclaration && firstValueDeclaration) {
79077937
result.valueDeclaration = firstValueDeclaration;
@@ -7938,7 +7968,7 @@ namespace ts {
79387968
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
79397969
const property = getUnionOrIntersectionProperty(type, name);
79407970
// We need to filter out partial properties in union types
7941-
return property && !(getCheckFlags(property) & CheckFlags.Partial) ? property : undefined;
7971+
return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined;
79427972
}
79437973

79447974
/**
@@ -12277,25 +12307,6 @@ namespace ts {
1227712307
return true;
1227812308
}
1227912309

12280-
function isUnionOrIntersectionTypeWithoutNullableConstituents(type: Type): boolean {
12281-
if (!(type.flags & TypeFlags.UnionOrIntersection)) {
12282-
return false;
12283-
}
12284-
// at this point we know that this is union or intersection type possibly with nullable constituents.
12285-
// check if we still will have compound type if we ignore nullable components.
12286-
let seenNonNullable = false;
12287-
for (const t of (<UnionOrIntersectionType>type).types) {
12288-
if (t.flags & TypeFlags.Nullable) {
12289-
continue;
12290-
}
12291-
if (seenNonNullable) {
12292-
return true;
12293-
}
12294-
seenNonNullable = true;
12295-
}
12296-
return false;
12297-
}
12298-
1229912310
/**
1230012311
* Compare two types and return
1230112312
* * Ternary.True if they are related with no assumptions,
@@ -12350,21 +12361,15 @@ namespace ts {
1235012361
isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
1235112362

1235212363
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
12353-
if (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) {
12364+
const isPerformingExcessPropertyChecks = (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral);
12365+
if (isPerformingExcessPropertyChecks) {
1235412366
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
1235512367
if (hasExcessProperties(<FreshObjectLiteralType>source, target, discriminantType, reportErrors)) {
1235612368
if (reportErrors) {
1235712369
reportRelationError(headMessage, source, target);
1235812370
}
1235912371
return Ternary.False;
1236012372
}
12361-
// Above we check for excess properties with respect to the entire target type. When union
12362-
// and intersection types are further deconstructed on the target side, we don't want to
12363-
// make the check again (as it might fail for a partial target type). Therefore we obtain
12364-
// the regular source type and proceed with that.
12365-
if (isUnionOrIntersectionTypeWithoutNullableConstituents(target) && !discriminantType) {
12366-
source = getRegularTypeOfObjectLiteral(source);
12367-
}
1236812373
}
1236912374

1237012375
if (relation !== comparableRelation && !isApparentIntersectionConstituent &&
@@ -12400,11 +12405,24 @@ namespace ts {
1240012405
}
1240112406
else {
1240212407
if (target.flags & TypeFlags.Union) {
12403-
result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
12408+
result = typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
12409+
if (result && isPerformingExcessPropertyChecks) {
12410+
// Validate against excess props using the original `source`
12411+
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
12412+
if (!propertiesRelatedTo(source, discriminantType || target, reportErrors)) {
12413+
return Ternary.False;
12414+
}
12415+
}
1240412416
}
1240512417
else if (target.flags & TypeFlags.Intersection) {
1240612418
isIntersectionConstituent = true; // set here to affect the following trio of checks
12407-
result = typeRelatedToEachType(source, target as IntersectionType, reportErrors);
12419+
result = typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors);
12420+
if (result && isPerformingExcessPropertyChecks) {
12421+
// Validate against excess props using the original `source`
12422+
if (!propertiesRelatedTo(source, target, reportErrors)) {
12423+
return Ternary.False;
12424+
}
12425+
}
1240812426
}
1240912427
else if (source.flags & TypeFlags.Intersection) {
1241012428
// Check to see if any constituents of the intersection are immediately related to the target.
@@ -12507,7 +12525,7 @@ namespace ts {
1250712525
// check excess properties against discriminant type only, not the entire union
1250812526
return hasExcessProperties(source, discriminant, /*discriminant*/ undefined, reportErrors);
1250912527
}
12510-
for (const prop of getPropertiesOfObjectType(source)) {
12528+
for (const prop of getPropertiesOfType(source)) {
1251112529
if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
1251212530
if (reportErrors) {
1251312531
// Report error in terms of object types in the target as those are the only ones
@@ -13234,7 +13252,9 @@ namespace ts {
1323413252
}
1323513253
}
1323613254
}
13237-
const properties = getPropertiesOfObjectType(target);
13255+
// We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_
13256+
// from the target union, across all members
13257+
const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target);
1323813258
for (const targetProp of properties) {
1323913259
if (!(targetProp.flags & SymbolFlags.Prototype)) {
1324013260
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
@@ -13282,7 +13302,8 @@ namespace ts {
1328213302
}
1328313303
return Ternary.False;
1328413304
}
13285-
const related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors);
13305+
// If the target comes from a partial union prop, allow `undefined` in the target type
13306+
const related = isRelatedTo(getTypeOfSymbol(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors);
1328613307
if (!related) {
1328713308
if (reportErrors) {
1328813309
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
@@ -14628,9 +14649,9 @@ namespace ts {
1462814649
}
1462914650

1463014651
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean) {
14631-
const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>target) : getPropertiesOfObjectType(target);
14652+
const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target);
1463214653
for (const targetProp of properties) {
14633-
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
14654+
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) {
1463414655
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
1463514656
if (!sourceProp) {
1463614657
yield targetProp;
@@ -15001,12 +15022,11 @@ namespace ts {
1500115022
}
1500215023
// If no inferences can be made to K's constraint, infer from a union of the property types
1500315024
// in the source to the template type X.
15004-
const valueTypes = compact([
15005-
getIndexTypeOfType(source, IndexKind.String),
15006-
getIndexTypeOfType(source, IndexKind.Number),
15007-
...map(getPropertiesOfType(source), getTypeOfSymbol)
15008-
]);
15009-
inferFromTypes(getUnionType(valueTypes), getTemplateTypeFromMappedType(target));
15025+
const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol);
15026+
const stringIndexType = getIndexTypeOfType(source, IndexKind.String);
15027+
const numberIndexInfo = getNonEnumNumberIndexInfo(source);
15028+
const numberIndexType = numberIndexInfo && numberIndexInfo.type;
15029+
inferFromTypes(getUnionType(append(append(propTypes, stringIndexType), numberIndexType)), getTemplateTypeFromMappedType(target));
1501015030
return true;
1501115031
}
1501215032
return false;

0 commit comments

Comments
 (0)