Skip to content

Code fails noImplicitAny check under 1.1.0.0 #833

Closed

Description

@paf31

This code used to compile without error under 1.0:

module M {

        export interface T<A> {
            get(): A;
        }

        export function ap<A, B>(f: T<(a: A) => B>, x: T<A>): T<B> {
            return {
                get: () => f.get()(x.get())
            };
        }

        export function map<A, B>(f: (a: A) => B, x: T<A>): T<B> {
            return {
                get: () => f(x.get())
            };
        }

        var x: T<number> = {
            get: () => 0
        };

        var test = ap(ap(map((a: number) => (b: number) => (c: number) => {
                return { a: a, b: b, c: c };
            }, x), x), x);
}

However, under 1.1, I get the following error:

(23,37): error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

I don't see any reason why any subexpression of test should have an inferred type of any.

Activity

  1. mhegazy commented on Oct 6, 2014

    @mhegazy
    Contributor

    This is relates to #641 though it is slightly different.

    In 1.0 we used to suppress contextual type propagation for return expression if there are any type annotation on a parameter. so in (c:number) => {} we ignored the contextual type for the return value because c was annotated. in 1.1 we changed that to only do it if you have an explicit return type annotation. the result is that the compiler will try to figure out the contextual type, as the complier is inferring the type for map, that would lead to a cycle, and to break it, the return type will be any.

    Note, that this used to happen before in 1.0 as well, but silently. we have added the noImplicitAny reporting for this to give the user some insight in how the compiler is reasoning about the input.

    adding an explicit annotation would resolve the issue, also c

    var f = (a: number) => (b: number) =>  (c: number) => {
        return { a: a, b: b, c: c };
    };
    var test = ap(ap(map(f, x), x), x);

    another one that would do the trick, but I would not recommend as it is subtle, is using parens around (c:number) => {}, to stop the flow of contextual type.

    var test = ap(ap(map((a: number) => (b: number) =>  ((c: number) => {
        return { a: a, b: b, c: c };
    }), x), x), x);
  2. paf31 commented on Oct 6, 2014

    @paf31
    Author

    Thanks for the explanation. I would say though that any type system bug which can be fixed by reparenthesizing subexpressions should not be "by design" :)

  3. mhegazy commented on Oct 6, 2014

    @mhegazy
    Contributor

    I do not believe it is a bug. it is a result of the current design. we have two options, either go into an infinite recursion trying to figure out the type of return statement, or break the loop with some value (any). The parenthesis, is a result of another design decision not to propagate contextual type through expressions, and allowing the user to opt-out of contextual type if they so choose.

  4. paf31 commented on Oct 6, 2014

    @paf31
    Author

    Where can I find documentation on "contextual types"?

  5. RyanCavanaugh commented on Oct 6, 2014

    @RyanCavanaugh
    Member

    Section 4.19 of the spec

  6. zpdDG4gta8XKpMCd commented on Jun 28, 2015

    @zpdDG4gta8XKpMCd

    is this by design too?

    function apply<a, r>(value: a, map: (value: a) => r): r {
        return map(value);
    }
    function id<a>(value: a) : a { return value; }
    var yay = apply(() => ({ x: 0 }), id); // () => any <--- ????
    
    
    // at the same time
    
    var huh = () => ({ x: 0 }) // () => { x: number } <-- i am all right
    
    // then
    
    function always<a>(value: a): () => a { return () => value; }
    
    var ugh = apply(always({ x: 0 }), id); // () => { x: number } <-- look, i fixed it!
    
    // all this just doesn't make any sense

    god, if anything please fix the inference first

  7. RyanCavanaugh commented on Jun 28, 2015

    @RyanCavanaugh
    Member

    I will let Fred Brooks know that developer time is completely fungible and that it would be plausible to take the intern off his summer project to redesign how generic type inference works.

  8. paf31 commented on Jun 28, 2015

    @paf31
    Author

    I will let Fred Brooks know that developer time is completely fungible and that it would be plausible to take the intern off his summer project to redesign how generic type inference works.

    What is this in response to?

  9. RyanCavanaugh commented on Jun 28, 2015

    @RyanCavanaugh
    Member

    Aleksey's comment that we should change this instead of doing abstract

  10. zpdDG4gta8XKpMCd commented on Jun 28, 2015

    @zpdDG4gta8XKpMCd

    sarcasm, i has it too

    seriously, why do new controversial OOP features take precedence over not
    working inference let alone anything that supports coding in functional
    style?
    On Jun 28, 2015 6:20 PM, "Ryan Cavanaugh" notifications@github.com wrote:

    Aleksey's comment that we should change this instead of doing abstract

    —
    Reply to this email directly or view it on GitHub
    #833 (comment)
    .

  11. RyanCavanaugh commented on Jun 29, 2015

    @RyanCavanaugh
    Member

    It's not a matter of precedence.

    Choosing not to do abstract will not a) make fixing this any easier or b) free up any resources that are capable of fixing this problem.

  12. danquirk commented on Jun 29, 2015

    @danquirk
    Member

    Aleksey-Bykov In addition to what's been covered, don't think we haven't spent a lot of time talking about generic type inference over the years. It's not like where inference is now is as far as we thought about it and we just punted on thinking about going any deeper. We'll continually re-evaluate what is and isn't feasible in that part of the system over time, but as Ryan notes, it's not as simple as just choosing to do x instead of y.

  13. zpdDG4gta8XKpMCd commented on Jun 29, 2015

    @zpdDG4gta8XKpMCd

    Good to know. Thank you
    On Jun 29, 2015 3:43 PM, "Dan Quirk" notifications@github.com wrote:

    Aleksey-Bykov https://github.com/aleksey-bykov In addition to what's
    been covered, don't think we haven't spent a lot of time talking about
    generic type inference over the years. It's not like where inference is now
    is as far as we thought about it and we just punted on thinking about going
    any deeper. We'll continually re-evaluate what is and isn't feasible in
    that part of the system over time, but as Ryan notes, it's not as simple as
    just choosing to do x instead of y.

    —
    Reply to this email directly or view it on GitHub
    #833 (comment)
    .

  14. locked and limited conversation to collaborators on Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Breaking ChangeWould introduce errors in existing codeBy DesignDeprecated - use "Working as Intended" or "Design Limitation" instead

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions