Skip to content

Type parameters do not get fixed when the compiler visits the same signature multiple times #2378

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

Closed
JsonFreeman opened this issue Mar 16, 2015 · 8 comments · Fixed by #3787
Labels
Bug A bug in TypeScript

Comments

@JsonFreeman
Copy link
Contributor

JsonFreeman commented Mar 16, 2015

As of change #2356, the following code gives the correct result in the batch compiler:

declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
f(0, x => null, x => x.blahblah);

Namely, we infer T to be number, and we get an error on blahblah.

However, there are a few things still wrong:

  • The language service does not show the correct result. It shows both x's to be number, but if you hover on f, you will see that it was instantiated to any, instead of number.
  • If you add another overload, the wrong type argument gets inferred:
declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
declare function f();
f(0, x => null, x => x.blahblah);

Now suddenly blahblah is not an error, and the second x is any.

  • In theory, if this overload is not assignable, but it has already fixed the type parameter T, and another overload comes along with a type parameter in the same position, that second type parameter will not get fixed. I don't have a good repro for this, but it is certainly a possibility in theory.

All of these issues happen because when a function expression parameter causes a type parameter to get fixed, it only does so if it is affected by the type of that type parameter. I believe the right thing here is that if a function parameter aligns with the type parameter, it should still fix it, even if it has already been assigned a type in the past. That way, it will fix the type parameter no matter which signature is being visited, or whether this signature has been visited before.

I consider this bug a followup to bugs #2127 and #2182.

@DanielRosenwasser
Copy link
Member

Is this bug different from #2377?

@RyanCavanaugh
Copy link
Member

Is this a bug per the spec, or a suggested spec+implementation change?

@JsonFreeman JsonFreeman added the Duplicate An existing issue was already created label Mar 17, 2015
@JsonFreeman
Copy link
Contributor Author

Closing this as a duplicate of #2377. @RyanCavanaugh to answer your question, the spec is from 1.0, and the implementation has diverged significantly from the spec since the 1.0 days. So your question does not have a well defined answer.

@JsonFreeman
Copy link
Contributor Author

Actually, I'll make this the real one.

@JsonFreeman JsonFreeman reopened this Mar 17, 2015
@JsonFreeman JsonFreeman added Bug A bug in TypeScript and removed Duplicate An existing issue was already created labels Mar 17, 2015
@mhegazy mhegazy added this to the TypeScript 1.6 milestone Mar 25, 2015
@JsonFreeman
Copy link
Contributor Author

I have found a repro for my above theory about different signatures affecting the fixedness of each other's type parameters, and it is very strange indeed. Here it is:

declare function foo<T>(x: T, func: (p: T) => T): T;
//declare function foo<T>(x: T, func: (p: T) => T): T;

interface Base {
    baseProp;
}
interface Derived extends Base {
    toBase(): Base;
}

var derived: Derived;
var result = foo(derived, d => d.toBase());

With the example as is, we get an error. T gets inferred to Derived because it got fixed by the parameter d. And then we fail when we compare Derived => Base against Derived => Derived.

Now uncomment the second overload (notice that it's identical to the first). We no longer get an error, which is odd as it is, but in addition, T is inferred to Base instead of Derived. So result has type Base, whereas if the first overload did not give an error, it would have been type Derived. But if T is inferred to be Base, then the parameter d should be base, and we should have gotten an error on d.toBase().

This is why it is not sufficient to keep around information about each signature in case we visit it multiple times. We also have to prevent signatures from interfering with the type parameter state of other signatures.

@RyanCavanaugh
Copy link
Member

What's the deal with the in progress label?

@JsonFreeman
Copy link
Contributor Author

@danquirk is experimenting with an issue visualizer called waffle, which works off of the github labels. In addition to using the labels that we've created, it supplies some of its own, and tags our issues using its tags. "In progress" is one such tag that is included in waffle.

@danquirk
Copy link
Member

danquirk commented Jul 9, 2015

I've turned off the thing that causes the 'in progress' label to be created so people stop bugging me about it :) If people want to look at the waffle board for issue management they can: https://waffle.io/Microsoft/TypeScript

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript
Projects
None yet
5 participants