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

inference strangeness 6 #6611

Closed
zpdDG4gta8XKpMCd opened this issue Jan 25, 2016 · 7 comments
Closed

inference strangeness 6 #6611

zpdDG4gta8XKpMCd opened this issue Jan 25, 2016 · 7 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@zpdDG4gta8XKpMCd
Copy link

export interface A<a> {
    value: a;
}

function fn<a>(values: A<a>, value: a) : void {
}

let handlers: A<(value: number) => void>;
fn(handlers, value => alert(value)); // < -- expected value: number, actual value: any
@DanielRosenwasser DanielRosenwasser added the Bug A bug in TypeScript label Jan 25, 2016
@DanielRosenwasser
Copy link
Member

This one looks like a contextual typing bug.

@mhegazy mhegazy added this to the TypeScript 2.0 milestone Feb 24, 2016
@sandersn
Copy link
Member

sandersn commented Mar 7, 2016

Interestingly, the type parameter is inferred correctly and therefore the type of fn. Here is a cleaned up example that shows this:

interface Box<T> {
    x: T;
}
declare function f<U>(box: Box<U>, u: U): U;
let handlers: Box<(value: number) => void>;
let z = f(handlers, y => y.length); // expected error: 'length' not in 'number'

z: (value: number) => void as expected. So inference hasn't failed, it just failed to propagate its results to the lambda.

@sandersn
Copy link
Member

sandersn commented Mar 8, 2016

Working bottom up, I see that U is not instantiated when the contextual type of y => y.length is checked, which scuttles contextual type checking (U becomes {} which has no call signature, hence no contextual type). This is during the second round of inference, because contextually typed things like arrow functions are skipped in the first round.

Of course the first round discovers that Box<(value: number) => void> with the target Box<U> gives U = (value: number) => void. Unfortunately, even though the signature is instantiated with this information during the first round, it's thrown away at the beginning of the second round. This might be incorrect.

I'll try moving the code that re-initialises the signature before the inference loop. But I expect this will break something else.

@sandersn
Copy link
Member

sandersn commented Mar 8, 2016

Removing the per-loop reset breaks the compiler badly. An alternate approach is figuring out how to get checkDeferredNode to get its contextual type correctly. Right now enough nodes already have type 'any' that it gets the wrong answer too, but I'll see if it's possible to change.

@mhegazy mhegazy modified the milestones: TypeScript 2.1, TypeScript 2.0 Jun 8, 2016
@unional
Copy link
Contributor

unional commented Jun 27, 2016

Another case (let me know if you want to open a new issue for this):

interface Foo {
  init?: () => void;
}

let x: Foo = getX();
if (x.init) {
  x.init();  // Works fine
  let y = () => {
    x.init(); // Object is possibly 'undefined';
  }
}

@DanielRosenwasser
Copy link
Member

@unional that's unrelated to this, and behaving as expected. Control-flow-based type analysis doesn't work across function expressions because the value can change at a different point in time.

@unional
Copy link
Contributor

unional commented Jun 28, 2016

Ah, I see. Thanks! 😛

@mhegazy mhegazy modified the milestones: Future, TypeScript 2.1 Sep 29, 2016
@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Mar 28, 2019
@ahejlsberg ahejlsberg modified the milestones: Backlog, TypeScript 3.5.0 Mar 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

6 participants