Skip to content
Closed
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
33 changes: 31 additions & 2 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -16441,7 +16441,12 @@ func (c *Checker) getNonMissingTypeOfSymbol(symbol *ast.Symbol) *Type {
func (c *Checker) getTypeOfInstantiatedSymbol(symbol *ast.Symbol) *Type {
links := c.valueSymbolLinks.Get(symbol)
if links.resolvedType == nil {
links.resolvedType = c.instantiateType(c.getTypeOfSymbol(links.target), links.mapper)
declaration := links.target.ValueDeclaration
t := c.instantiateType(c.getTypeOfSymbol(links.target), links.mapper)
if declaration != nil && ast.IsParameterDeclaration(declaration) && hasDotDotDotToken(declaration) {
t = c.normalizeNoInferSpread(t)
}
links.resolvedType = t
}
return links.resolvedType
}
Expand Down Expand Up @@ -16518,9 +16523,14 @@ func (c *Checker) getTypeOfVariableOrParameterOrPropertyWorker(symbol *ast.Symbo
}
var result *Type
switch declaration.Kind {
case ast.KindParameter, ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindVariableDeclaration,
case ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindVariableDeclaration,
ast.KindBindingElement:
result = c.getWidenedTypeForVariableLikeDeclaration(declaration, true /*reportErrors*/)
case ast.KindParameter:
result = c.getWidenedTypeForVariableLikeDeclaration(declaration, true /*reportErrors*/)
if hasDotDotDotToken(declaration) {
result = c.normalizeNoInferSpread(result)
}
case ast.KindPropertyAssignment:
result = c.checkPropertyAssignment(declaration, CheckModeNormal)
case ast.KindShorthandPropertyAssignment:
Expand Down Expand Up @@ -23215,6 +23225,12 @@ func (c *Checker) createNormalizedTupleTypeEx(target *Type, elementTypes []*Type
return c.createTypeReferenceEx(target, elementTypes, objectFlags)
}
if d.combinedFlags&ElementFlagsVariadic != 0 {
elementTypes = core.SameMapIndex(elementTypes, func(t *Type, i int) *Type {
if i < len(d.elementInfos) && d.elementInfos[i].flags&ElementFlagsVariadic != 0 {
return c.normalizeNoInferSpread(t)
}
return t
})
for i, e := range elementTypes {
if i < len(d.elementInfos) && d.elementInfos[i].flags&ElementFlagsVariadic != 0 && e.flags&(TypeFlagsNever|TypeFlagsUnion) != 0 {
// Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z]
Expand Down Expand Up @@ -23256,6 +23272,19 @@ func (c *Checker) createNormalizedTupleTypeEx(target *Type, elementTypes []*Type
return tupleTarget
}

func (c *Checker) normalizeNoInferSpread(t *Type) *Type {
if !c.isNoInferType(t) {
return t
}
return c.mapType(t.AsSubstitutionType().baseType, func(element *Type) *Type {
if !isTupleType(element) {
return c.getNoInferType(t)
}
Comment on lines +23279 to +23282
target := element.TargetTupleType()
return c.createTupleTypeEx(core.Map(c.getElementTypes(element), c.getNoInferType), target.elementInfos, target.readonly)
})
}

func (c *Checker) createNormalizedTupleType(target *Type, elementTypes []*Type) *Type {
return c.createNormalizedTupleTypeEx(target, elementTypes, ObjectFlagsNone)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
noInferRestSpread1.ts(7,22): error TS2345: Argument of type '(a: number, b: number) => void' is not assignable to parameter of type '(args_0: number) => void'.
Target signature provides too few arguments. Expected 2 or more, but got 1.


==== noInferRestSpread1.ts (1 errors) ====
declare function call<A extends readonly unknown[]>(
arg: (...args: NoInfer<A>) => void,
...args: A
): A;

const result1 = call((a: number) => {}, 1, 2);
const result2 = call((a: number, b: number) => {}, 1); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(a: number, b: number) => void' is not assignable to parameter of type '(args_0: number) => void'.
!!! error TS2345: Target signature provides too few arguments. Expected 2 or more, but got 1.
const result3 = call((a) => {}, 1, ''); // test contextual parameters
const result4 = call((a, b) => {}, 1, ''); // test contextual parameters
const result5 = call((...args) => {}, 1, ''); // test contextual parameters
const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters

declare function fn1<A extends unknown[]>(
cb: (a: [number, ...NoInfer<A>]) => void,
args: A,
): A;

declare const singleStr: [string];

const result7 = fn1((arg) => {
arg.length;
}, singleStr);

declare const tupleUnion: [string] | [number, boolean];

const result8 = fn1((arg) => {
arg.length;
}, tupleUnion);

declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void;

fn2((a, ...rest) => {});

113 changes: 113 additions & 0 deletions testdata/baselines/reference/conformance/noInferRestSpread1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts] ////

=== noInferRestSpread1.ts ===
declare function call<A extends readonly unknown[]>(
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22))

arg: (...args: NoInfer<A>) => void,
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 0, 52))
>args : Symbol(args, Decl(noInferRestSpread1.ts, 1, 8))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22))

...args: A
>args : Symbol(args, Decl(noInferRestSpread1.ts, 1, 37))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22))

): A;
>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22))

const result1 = call((a: number) => {}, 1, 2);
>result1 : Symbol(result1, Decl(noInferRestSpread1.ts, 5, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 5, 22))

const result2 = call((a: number, b: number) => {}, 1); // error
>result2 : Symbol(result2, Decl(noInferRestSpread1.ts, 6, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 6, 22))
>b : Symbol(b, Decl(noInferRestSpread1.ts, 6, 32))

const result3 = call((a) => {}, 1, ''); // test contextual parameters
>result3 : Symbol(result3, Decl(noInferRestSpread1.ts, 7, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 7, 22))

const result4 = call((a, b) => {}, 1, ''); // test contextual parameters
>result4 : Symbol(result4, Decl(noInferRestSpread1.ts, 8, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 8, 22))
>b : Symbol(b, Decl(noInferRestSpread1.ts, 8, 24))

const result5 = call((...args) => {}, 1, ''); // test contextual parameters
>result5 : Symbol(result5, Decl(noInferRestSpread1.ts, 9, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>args : Symbol(args, Decl(noInferRestSpread1.ts, 9, 22))

const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters
>result6 : Symbol(result6, Decl(noInferRestSpread1.ts, 10, 5))
>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 10, 22))
>rest : Symbol(rest, Decl(noInferRestSpread1.ts, 10, 24))

declare function fn1<A extends unknown[]>(
>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21))

cb: (a: [number, ...NoInfer<A>]) => void,
>cb : Symbol(cb, Decl(noInferRestSpread1.ts, 12, 42))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 13, 7))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21))

args: A,
>args : Symbol(args, Decl(noInferRestSpread1.ts, 13, 43))
>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21))

): A;
>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21))

declare const singleStr: [string];
>singleStr : Symbol(singleStr, Decl(noInferRestSpread1.ts, 17, 13))

const result7 = fn1((arg) => {
>result7 : Symbol(result7, Decl(noInferRestSpread1.ts, 19, 5))
>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48))
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 19, 21))

arg.length;
>arg.length : Symbol(length)
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 19, 21))
>length : Symbol(length)

}, singleStr);
>singleStr : Symbol(singleStr, Decl(noInferRestSpread1.ts, 17, 13))

declare const tupleUnion: [string] | [number, boolean];
>tupleUnion : Symbol(tupleUnion, Decl(noInferRestSpread1.ts, 23, 13))

const result8 = fn1((arg) => {
>result8 : Symbol(result8, Decl(noInferRestSpread1.ts, 25, 5))
>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48))
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 25, 21))

arg.length;
>arg.length : Symbol(length)
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 25, 21))
>length : Symbol(length)

}, tupleUnion);
>tupleUnion : Symbol(tupleUnion, Decl(noInferRestSpread1.ts, 23, 13))

declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void;
>fn2 : Symbol(fn2, Decl(noInferRestSpread1.ts, 27, 15))
>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 29, 21))
>args : Symbol(args, Decl(noInferRestSpread1.ts, 29, 27))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))

fn2((a, ...rest) => {});
>fn2 : Symbol(fn2, Decl(noInferRestSpread1.ts, 27, 15))
>a : Symbol(a, Decl(noInferRestSpread1.ts, 31, 5))
>rest : Symbol(rest, Decl(noInferRestSpread1.ts, 31, 7))

131 changes: 131 additions & 0 deletions testdata/baselines/reference/conformance/noInferRestSpread1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts] ////

=== noInferRestSpread1.ts ===
declare function call<A extends readonly unknown[]>(
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A

arg: (...args: NoInfer<A>) => void,
>arg : (...args: NoInfer<A>) => void
>args : NoInfer<A>

...args: A
>args : A

): A;

const result1 = call((a: number) => {}, 1, 2);
>result1 : [number, number]
>call((a: number) => {}, 1, 2) : [number, number]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(a: number) => {} : (a: number) => void
>a : number
>1 : 1
>2 : 2

const result2 = call((a: number, b: number) => {}, 1); // error
>result2 : [number]
>call((a: number, b: number) => {}, 1) : [number]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(a: number, b: number) => {} : (a: number, b: number) => void
>a : number
>b : number
>1 : 1

const result3 = call((a) => {}, 1, ''); // test contextual parameters
>result3 : [number, string]
>call((a) => {}, 1, '') : [number, string]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(a) => {} : (a: number) => void
>a : number
>1 : 1
>'' : ""

const result4 = call((a, b) => {}, 1, ''); // test contextual parameters
>result4 : [number, string]
>call((a, b) => {}, 1, '') : [number, string]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(a, b) => {} : (a: number, b: string) => void
>a : number
>b : string
>1 : 1
>'' : ""

const result5 = call((...args) => {}, 1, ''); // test contextual parameters
>result5 : [number, string]
>call((...args) => {}, 1, '') : [number, string]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(...args) => {} : (args_0: number, args_1: string) => void
>args : [number, string]
>1 : 1
>'' : ""

const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters
>result6 : [number, string]
>call((a, ...rest) => {}, 1, '') : [number, string]
>call : <A extends readonly unknown[]>(arg: (...args: NoInfer<A>) => void, ...args: A) => A
>(a, ...rest) => {} : (a: number, rest_0: string) => void
>a : number
>rest : [string]
>1 : 1
>'' : ""

declare function fn1<A extends unknown[]>(
>fn1 : <A extends unknown[]>(cb: (a: [number, ...NoInfer<A>]) => void, args: A) => A

cb: (a: [number, ...NoInfer<A>]) => void,
>cb : (a: [number, ...NoInfer<A>]) => void
>a : [number, ...NoInfer<A>]

args: A,
>args : A

): A;

declare const singleStr: [string];
>singleStr : [string]

const result7 = fn1((arg) => {
>result7 : [string]
>fn1((arg) => { arg.length;}, singleStr) : [string]
>fn1 : <A extends unknown[]>(cb: (a: [number, ...NoInfer<A>]) => void, args: A) => A
>(arg) => { arg.length;} : (arg: [number, string]) => void
>arg : [number, string]

arg.length;
>arg.length : 2
>arg : [number, string]
>length : 2

}, singleStr);
>singleStr : [string]

declare const tupleUnion: [string] | [number, boolean];
>tupleUnion : [string] | [number, boolean]

const result8 = fn1((arg) => {
>result8 : [string] | [number, boolean]
>fn1((arg) => { arg.length;}, tupleUnion) : [string] | [number, boolean]
>fn1 : <A extends unknown[]>(cb: (a: [number, ...NoInfer<A>]) => void, args: A) => A
>(arg) => { arg.length;} : (arg: [number, string] | [number, number, boolean]) => void
>arg : [number, string] | [number, number, boolean]

arg.length;
>arg.length : 2 | 3
>arg : [number, string] | [number, number, boolean]
>length : 2 | 3

}, tupleUnion);
>tupleUnion : [string] | [number, boolean]

declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void;
>fn2 : (arg: (...args: NoInfer<[string, number]>) => void) => void
>arg : (args_0: string, args_1: number) => void
>args : [string, number]

fn2((a, ...rest) => {});
>fn2((a, ...rest) => {}) : void
>fn2 : (arg: (...args: NoInfer<[string, number]>) => void) => void
>(a, ...rest) => {} : (a: string, rest_0: number) => void
>a : string
>rest : [number]

Loading