Skip to content

Commit ec0b88f

Browse files
committed
just reuse existing CheckMode.RestBindingElement
1 parent 5035583 commit ec0b88f

10 files changed

+935
-52
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,6 @@ export const enum CheckMode {
13391339
// e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`,
13401340
// we need to preserve generic types instead of substituting them for constraints
13411341
TypeOnly = 1 << 6, // Called from getTypeOfExpression, diagnostics may be omitted
1342-
SkipConstraintsSubstitution = 1 << 7,
13431342
}
13441343

13451344
/** @internal */
@@ -11528,9 +11527,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1152811527

1152911528
// Return the type of a binding element parent. We check SymbolLinks first to see if a type has been
1153011529
// assigned by contextual typing.
11531-
function getTypeForBindingElementParent(node: BindingElementGrandparent, checkMode: CheckMode) {
11532-
const symbol = getSymbolOfDeclaration(node);
11533-
return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode);
11530+
function getTypeForBindingElementParent(node: BindingElement) {
11531+
const grandparent = node.parent.parent;
11532+
const rootParameter = tryGetRootParameterDeclaration(node);
11533+
if (rootParameter) {
11534+
const symbol = getSymbolOfDeclaration(grandparent);
11535+
const contextualParameterType = symbol && getSymbolLinks(symbol).type;
11536+
if (contextualParameterType) {
11537+
return contextualParameterType;
11538+
}
11539+
}
11540+
return getTypeForVariableLikeDeclaration(grandparent, /*includeOptionality*/ false, node.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal);
1153411541
}
1153511542

1153611543
function getRestType(source: Type, properties: PropertyName[], symbol: Symbol | undefined): Type {
@@ -11663,8 +11670,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1166311670

1166411671
/** Return the inferred type for a binding element */
1166511672
function getTypeForBindingElement(declaration: BindingElement): Type | undefined {
11666-
const checkMode = declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal;
11667-
const parentType = getTypeForBindingElementParent(declaration.parent.parent, checkMode);
11673+
const parentType = getTypeForBindingElementParent(declaration);
1166811674
return parentType && getBindingElementTypeFromParentType(declaration, parentType, /*noTupleBoundsCheck*/ false);
1166911675
}
1167011676

@@ -30363,27 +30369,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3036330369
return contextualType && !isGenericType(contextualType);
3036430370
}
3036530371

30366-
function shouldSubstituteConstraints(type: Type, reference: Node, checkMode?: CheckMode) {
30372+
function getNarrowableTypeForReference(type: Type, reference: Node, checkMode = CheckMode.Normal) {
30373+
if (isNoInferType(type)) {
30374+
type = (type as SubstitutionType).baseType;
30375+
}
3036730376
// When the type of a reference is or contains an instantiable type with a union type constraint, and
3036830377
// when the reference is in a constraint position (where it is known we'll obtain the apparent type) or
3036930378
// has a contextual type containing no top-level instantiables (meaning constraints will determine
3037030379
// assignability), we substitute constraints for all instantiables in the type of the reference to give
3037130380
// control flow analysis an opportunity to narrow it further. For example, for a reference of a type
3037230381
// parameter type 'T extends string | undefined' with a contextual type 'string', we substitute
3037330382
// 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'.
30374-
return !(checkMode && checkMode & CheckMode.Inferential) &&
30383+
const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) &&
3037530384
someType(type, isGenericTypeWithUnionConstraint) &&
3037630385
(isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode));
30377-
}
30378-
30379-
function getNarrowableTypeForReference(type: Type, reference: Node, checkMode = CheckMode.Normal) {
30380-
if (isNoInferType(type)) {
30381-
type = (type as SubstitutionType).baseType;
30382-
}
30383-
if (checkMode & CheckMode.SkipConstraintsSubstitution) {
30384-
return type;
30385-
}
30386-
return shouldSubstituteConstraints(type, reference, checkMode) ? mapType(type, getBaseConstraintOrType) : type;
30386+
return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type;
3038730387
}
3038830388

3038930389
function isExportOrExportExpression(location: Node) {
@@ -30845,7 +30845,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3084530845
const links = getNodeLinks(parent);
3084630846
if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) {
3084730847
links.flags |= NodeCheckFlags.InCheckIdentifier;
30848-
const parentType = getTypeForBindingElementParent(parent, shouldSubstituteConstraints(type, location) ? CheckMode.Normal : CheckMode.SkipConstraintsSubstitution);
30848+
const parentType = getTypeForBindingElementParent(declaration);
3084930849
const parentNarrowableType = parentType && getNarrowableTypeForReference(parentType, location);
3085030850

3085130851
links.flags &= ~NodeCheckFlags.InCheckIdentifier;
@@ -44922,8 +44922,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4492244922

4492344923
// check private/protected variable access
4492444924
const parent = node.parent.parent;
44925-
const parentCheckMode = node.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal;
44926-
const parentType = getTypeForBindingElementParent(parent, parentCheckMode);
44925+
const parentType = getTypeForBindingElementParent(node);
4492744926
const name = node.propertyName || node.name;
4492844927
if (parentType && !isBindingPattern(name)) {
4492944928
const exprType = getLiteralTypeFromPropertyName(name);

tests/baselines/reference/dependentDestructuredRestVariables1.symbols

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -152,64 +152,93 @@ const fn1 = <P extends Params1>(params: P) => {
152152

153153
};
154154

155+
const fn2 = <P extends Params1>({ foo, ...rest }: P) => {
156+
>fn2 : Symbol(fn2, Decl(dependentDestructuredRestVariables1.tsx, 56, 5))
157+
>P : Symbol(P, Decl(dependentDestructuredRestVariables1.tsx, 56, 13))
158+
>Params1 : Symbol(Params1, Decl(dependentDestructuredRestVariables1.tsx, 39, 1))
159+
>foo : Symbol(foo, Decl(dependentDestructuredRestVariables1.tsx, 56, 33))
160+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 56, 38))
161+
>P : Symbol(P, Decl(dependentDestructuredRestVariables1.tsx, 56, 13))
162+
163+
if (rest.tag === "a") {
164+
>rest.tag : Symbol(tag, Decl(dependentDestructuredRestVariables1.tsx, 43, 6), Decl(dependentDestructuredRestVariables1.tsx, 43, 35))
165+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 56, 38))
166+
>tag : Symbol(tag, Decl(dependentDestructuredRestVariables1.tsx, 43, 6), Decl(dependentDestructuredRestVariables1.tsx, 43, 35))
167+
168+
rest.type.toFixed(); // ok
169+
>rest.type.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
170+
>rest.type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 43, 16))
171+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 56, 38))
172+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 43, 16))
173+
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
174+
175+
return rest; // Omit<P, "foo">
176+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 56, 38))
177+
}
178+
179+
return undefined;
180+
>undefined : Symbol(undefined)
181+
182+
};
183+
155184
// https://github.com/microsoft/TypeScript/issues/53947
156185

157186
function ImageAvatar(props: { className?: string; src: string }) {
158-
>ImageAvatar : Symbol(ImageAvatar, Decl(dependentDestructuredRestVariables1.tsx, 54, 2))
159-
>props : Symbol(props, Decl(dependentDestructuredRestVariables1.tsx, 58, 21))
160-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 58, 29))
161-
>src : Symbol(src, Decl(dependentDestructuredRestVariables1.tsx, 58, 49))
187+
>ImageAvatar : Symbol(ImageAvatar, Decl(dependentDestructuredRestVariables1.tsx, 63, 2))
188+
>props : Symbol(props, Decl(dependentDestructuredRestVariables1.tsx, 67, 21))
189+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 67, 29))
190+
>src : Symbol(src, Decl(dependentDestructuredRestVariables1.tsx, 67, 49))
162191

163192
return null;
164193
}
165194

166195
function InitialsAvatar(props: { className?: string; name: string }) {
167-
>InitialsAvatar : Symbol(InitialsAvatar, Decl(dependentDestructuredRestVariables1.tsx, 60, 1))
168-
>props : Symbol(props, Decl(dependentDestructuredRestVariables1.tsx, 62, 24))
169-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 62, 32))
170-
>name : Symbol(name, Decl(dependentDestructuredRestVariables1.tsx, 62, 52))
196+
>InitialsAvatar : Symbol(InitialsAvatar, Decl(dependentDestructuredRestVariables1.tsx, 69, 1))
197+
>props : Symbol(props, Decl(dependentDestructuredRestVariables1.tsx, 71, 24))
198+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 71, 32))
199+
>name : Symbol(name, Decl(dependentDestructuredRestVariables1.tsx, 71, 52))
171200

172201
return null;
173202
}
174203

175204
type AvatarProps =
176-
>AvatarProps : Symbol(AvatarProps, Decl(dependentDestructuredRestVariables1.tsx, 64, 1))
205+
>AvatarProps : Symbol(AvatarProps, Decl(dependentDestructuredRestVariables1.tsx, 73, 1))
177206

178207
| { type: "image"; src: string; className: string }
179-
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 67, 5))
180-
>src : Symbol(src, Decl(dependentDestructuredRestVariables1.tsx, 67, 20))
181-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 67, 33))
208+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 76, 5))
209+
>src : Symbol(src, Decl(dependentDestructuredRestVariables1.tsx, 76, 20))
210+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 76, 33))
182211

183212
| { type: "initials"; name: string; className: string };
184-
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 68, 5))
185-
>name : Symbol(name, Decl(dependentDestructuredRestVariables1.tsx, 68, 23))
186-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 68, 37))
213+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 77, 5))
214+
>name : Symbol(name, Decl(dependentDestructuredRestVariables1.tsx, 77, 23))
215+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 77, 37))
187216

188217
const Avatar = ({ type, className, ...rest }: AvatarProps) => {
189-
>Avatar : Symbol(Avatar, Decl(dependentDestructuredRestVariables1.tsx, 70, 5))
190-
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 70, 17))
191-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 70, 23))
192-
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 70, 34))
193-
>AvatarProps : Symbol(AvatarProps, Decl(dependentDestructuredRestVariables1.tsx, 64, 1))
218+
>Avatar : Symbol(Avatar, Decl(dependentDestructuredRestVariables1.tsx, 79, 5))
219+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 79, 17))
220+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 79, 23))
221+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 79, 34))
222+
>AvatarProps : Symbol(AvatarProps, Decl(dependentDestructuredRestVariables1.tsx, 73, 1))
194223

195224
if (type === "image") {
196-
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 70, 17))
225+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 79, 17))
197226

198227
return <ImageAvatar className={className} {...rest} />;
199-
>ImageAvatar : Symbol(ImageAvatar, Decl(dependentDestructuredRestVariables1.tsx, 54, 2))
200-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 72, 23))
201-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 70, 23))
202-
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 70, 34))
228+
>ImageAvatar : Symbol(ImageAvatar, Decl(dependentDestructuredRestVariables1.tsx, 63, 2))
229+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 81, 23))
230+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 79, 23))
231+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 79, 34))
203232
}
204233

205234
if (type === "initials") {
206-
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 70, 17))
235+
>type : Symbol(type, Decl(dependentDestructuredRestVariables1.tsx, 79, 17))
207236

208237
return <InitialsAvatar className={className} {...rest} />;
209-
>InitialsAvatar : Symbol(InitialsAvatar, Decl(dependentDestructuredRestVariables1.tsx, 60, 1))
210-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 76, 26))
211-
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 70, 23))
212-
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 70, 34))
238+
>InitialsAvatar : Symbol(InitialsAvatar, Decl(dependentDestructuredRestVariables1.tsx, 69, 1))
239+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 85, 26))
240+
>className : Symbol(className, Decl(dependentDestructuredRestVariables1.tsx, 79, 23))
241+
>rest : Symbol(rest, Decl(dependentDestructuredRestVariables1.tsx, 79, 34))
213242
}
214243

215244
throw new Error("");

tests/baselines/reference/dependentDestructuredRestVariables1.types

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,53 @@ const fn1 = <P extends Params1>(params: P) => {
268268

269269
};
270270

271+
const fn2 = <P extends Params1>({ foo, ...rest }: P) => {
272+
>fn2 : <P extends Params1>({ foo, ...rest }: P) => Omit<P, "foo"> | undefined
273+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
274+
><P extends Params1>({ foo, ...rest }: P) => { if (rest.tag === "a") { rest.type.toFixed(); // ok return rest; // Omit<P, "foo"> } return undefined;} : <P extends Params1>({ foo, ...rest }: P) => Omit<P, "foo"> | undefined
275+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
276+
>foo : string
277+
> : ^^^^^^
278+
>rest : Omit<P, "foo">
279+
> : ^^^^^^^^^^^^^^
280+
281+
if (rest.tag === "a") {
282+
>rest.tag === "a" : boolean
283+
> : ^^^^^^^
284+
>rest.tag : "a" | "b"
285+
> : ^^^^^^^^^
286+
>rest : { tag: "a"; type: number; } | { tag: "b"; type: string; }
287+
> : ^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^
288+
>tag : "a" | "b"
289+
> : ^^^^^^^^^
290+
>"a" : "a"
291+
> : ^^^
292+
293+
rest.type.toFixed(); // ok
294+
>rest.type.toFixed() : string
295+
> : ^^^^^^
296+
>rest.type.toFixed : (fractionDigits?: number) => string
297+
> : ^ ^^^ ^^^^^
298+
>rest.type : number
299+
> : ^^^^^^
300+
>rest : { tag: "a"; type: number; }
301+
> : ^^^^^^^ ^^^^^^^^ ^^^
302+
>type : number
303+
> : ^^^^^^
304+
>toFixed : (fractionDigits?: number) => string
305+
> : ^ ^^^ ^^^^^
306+
307+
return rest; // Omit<P, "foo">
308+
>rest : Omit<P, "foo">
309+
> : ^^^^^^^^^^^^^^
310+
}
311+
312+
return undefined;
313+
>undefined : undefined
314+
> : ^^^^^^^^^
315+
316+
};
317+
271318
// https://github.com/microsoft/TypeScript/issues/53947
272319

273320
function ImageAvatar(props: { className?: string; src: string }) {

0 commit comments

Comments
 (0)