Skip to content

wrong scope for async class member #6549

@beenotung

Description

@beenotung

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Versions

Output of ng --version:

@angular/cli: 1.0.6
node: 7.10.0
os: linux x64
@angular/animations: 4.1.3
@angular/common: 4.1.3
@angular/compiler: 4.1.3
@angular/core: 4.1.3
@angular/forms: 4.1.3
@angular/http: 4.1.3
@angular/platform-browser: 4.1.3
@angular/platform-browser-dynamic: 4.1.3
@angular/router: 4.1.3
@angular/cli: 1.0.6
@angular/compiler-cli: 4.1.3

Operation System: Archlinux x64

Output of uname -a:

Linux localhost 4.11.2-1-ARCH #1 SMP PREEMPT Mon May 22 06:53:49 CEST 2017 x86_64 GNU/Linux

Repro steps.

  1. create a project from seed ng new name
  2. config the tsconfig.json at project root
{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "src",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "allowJs": true,
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2015.promise",
      "es2016",
      "dom"
    ]
  }
}
  1. create and use a class with async method
export class Foo {
  async well(){
    return this.checkLogin();
  }
  async checkLogin() {
    return 'bar';
  }
}
new Foo.well()
  1. compile and serve the project ng build (no compile-time error is generated)
  2. view the website, see the console (run-time TypeError of "Cannot read property 'bar' of undefined" is generated)

The log given by the failure.

core.es5.js:1084 ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'checkLogin' of undefined
TypeError: Cannot read property 'checkLogin' of undefined
    at http://xxx/main.bundle.js:5732:54
    at step (http://xxx/main.bundle.js:5648:23)
    at Object.next (http://xxx/main.bundle.js:5629:53)
    at http://xxx/main.bundle.js:5623:71
    at new ZoneAwarePromise (http://xxx/polyfills.bundle.js:2856:29)
    at __awaiter (http://xxx/main.bundle.js:5619:12)
    at DocumentCenterService.uploadDocument (http://xxx/main.bundle.js:5728:16)
    at Array.map (native)
    at http://xxx/main.bundle.js:1121:50
    at step (http://xxx/main.bundle.js:1039:23)
    at resolvePromise (http://xxx/polyfills.bundle.js:2792:31)
    at http://xxx/polyfills.bundle.js:2718:17
    at rejected (http://xxx/main.bundle.js:10001:89)
    at ZoneDelegate.webpackJsonp.633.ZoneDelegate.invoke (http://xxx/polyfills.bundle.js:2414:26)
    at Object.onInvoke (http://xxx/vendor.bundle.js:8830:37)
    at ZoneDelegate.webpackJsonp.633.ZoneDelegate.invoke (http://xxx/polyfills.bundle.js:2413:32)
    at Zone.webpackJsonp.633.Zone.run (http://xxx/polyfills.bundle.js:2164:43)
    at http://xxx/polyfills.bundle.js:2840:57
    at ZoneDelegate.webpackJsonp.633.ZoneDelegate.invokeTask (http://xxx/polyfills.bundle.js:2447:31)
    at Object.onInvokeTask (http://xxx/vendor.bundle.js:8821:37)

It seems to fail because of the this is not the owner of the prototype but function passed to the generator.

Desired functionality.

The compiler shall use a variable to reference the scope and replace the usage of 'this'. An example of generated code:

DocumentCenterService.prototype.uploadDocument = function (file) {
        var _this = this;
        return __awaiter(this, void 0, void 0, function () {
            var desc, res, docID, formData, res2, fileID, uploadFile;
            return __generator(_this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, _this.checkLogin()];
                    

It should return a promise of 'bar' in above example without error.

Mention any other details that might be useful.

Sample of output bundled js

Notice there is a function at line 2 (instead of arrow function) and the this at line 6 is not escaped.

DocumentCenterService.prototype.uploadDocument = function (file) {
        return __awaiter(this, void 0, void 0, function () {
            var desc, res, docID, formData, res2, fileID, uploadFile;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.checkLogin()];
                    case 1:
                        _a.sent();
                        desc = new __WEBPACK_IMPORTED_MODULE_9__model_api_documentFileOverview__["a" /* model */].api.DocumentFileDescription(file);
            

Metadata

Metadata

Assignees

Labels

needs: investigationRequires some digging to determine if action is needed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions