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

Global variables in local functions are not control flow analysed #8472

Closed
tinganho opened this issue May 5, 2016 · 7 comments
Closed

Global variables in local functions are not control flow analysed #8472

tinganho opened this issue May 5, 2016 · 7 comments
Labels
Duplicate An existing issue was already created

Comments

@tinganho
Copy link
Contributor

tinganho commented May 5, 2016

str has been asserted it cannot be undefined on all call sites of test() below:

let str: string | undefined;
if (str) {
    test();
}

function test() {
    str.charAt(1); // error can be undefined
}
@kitsonk
Copy link
Contributor

kitsonk commented May 5, 2016

Essentially a dupe of #8720, #8367 and #7662 in that type guards get reset within functions, because the function body cannot be certain that is the only situation it will be invoked.

You could easily invoke test() any number of places outside of the scope of the current static analysis... You are assume that a non-module file is the "whole" of the programme, TypeScript cannot make that assumption.

@tinganho
Copy link
Contributor Author

tinganho commented May 5, 2016

You could easily invoke test() any number of places outside of the scope of the current static analysis

Though you can make the compiler check all those places for local functions and private methods.

If it wheren't private method or local functions then I would agree.

Here is the related class issue:

class A {
  private p: string | undefined;
  public a() {
    if (this.p) {
      this.b()
    }
  }
  private b() {
    this.p.charAt(1); // no error because it is checked in this.a()
  }
}

@tinganho
Copy link
Contributor Author

tinganho commented May 5, 2016

Just to extend my explanation:

The below code:

let str: string | undefined;
if (str) {
    test();
}

function test() {
    str.charAt(1); // error can be undefined
}

Could have been rewritten as:

let str: string | undefined;
if (str) {
    str.charAt(1);
}

Or

class A {
  private p: string | undefined;
  public a() {
    if (this.p) {
      this.b()
    }
  }
  private b() {
    this.p.charAt(1); // no error because it is checked in this.a()
  }
}

Could be rewritten as:

class A {
  private p: string | undefined;
  public a() {
    if (this.p) {
      this.p.charAt(1); 
    }
  }
}

These examples sort of entails that local functions/private methods are just inlined code blocks and therefore should be CFA:ed.

@kitsonk
Copy link
Contributor

kitsonk commented May 5, 2016

There is a big different between private and global variables. While at runtime there is no such thing as private at design time, you are contracting that no one outside of the "knowable" code is going to touch a private variable. But maybe I am missing something and the TypeScript team will elucidate I am sure.

@tinganho
Copy link
Contributor Author

tinganho commented May 5, 2016

@kitsonk

I think the compiler should consider whatever I declared it to be. Not based on what it is on runtime. If you try to access a declared private method publicly, you get a compile error anyway.

FWIW the local function below is private on runtime:

function f() {
  function local() {
  }
}

It also depends on your definitions of private. What I considered private on my OP, was for functions, it should be file scope private and every scope underneath it. And for class methods it is class scope private.

@mhegazy
Copy link
Contributor

mhegazy commented May 5, 2016

this issue is actually a duplicate/flip side proposal of #8353. you can find more details about why we can not do this in #8353 (comment), and more discussion in the design meeting notes at #8388.

where as it is theoretically possible to do some of these checks, by inlining function bodies in calls, or combining the control flow gram of all call sites as we enter a declaration, it would be a significant investment and a significant additional complexity tot he compiler logic that does not seem to warrant the value.

@mhegazy mhegazy closed this as completed May 5, 2016
@mhegazy mhegazy added the Duplicate An existing issue was already created label May 5, 2016
@tinganho
Copy link
Contributor Author

tinganho commented May 6, 2016

I hope you can consider doing the checks inside functions and methods. It is really a big source of unwraps ! for me. It is amazing how the CFA works, though I consider it having a big hole and not being feature complete if it doesn't consider functions and methods.

I preferably don't want to think that every refactor may introduce !. In an ideal world people shouldn't need to use !.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants