winglang / wing

A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚑
https://winglang.io
Other
5.06k stars 198 forks source link

Cannot reference preflight object through `if let` #5636

Open Chriscbr opened 9 months ago

Chriscbr commented 9 months ago

I tried this:

bring cloud;

class Foo {
  b: cloud.Bucket?;
  new() {
    this.b = new cloud.Bucket();
  }
  inflight list(): Array<str> {
    if let b = this.b {
      return b.list();
    }
  }
}

let f = new Foo();

This happened:

An error from wing compile

error: Expression of type "Bucket" references an unknown preflight object, can't qualify its capabilities (see https://github.com/winglang/wing/issues/76 for details)
   --> main.w:10:14
   |
10 |       return b.list();
   |              ^ Expression of type "Bucket" references an unknown preflight object, can't qualify its capabilities (see https://github.com/winglang/wing/issues/76 for details)

I expected this:

No response

Is there a workaround?

Use the original variable and unwrap it with the ! operator:

bring cloud;

class Foo {
  b: cloud.Bucket?;
  new() {
    this.b = new cloud.Bucket();
  }
  inflight list(): Array<str> {
    if let b = this.b {
      return this.b!.list();
    }
  }
}

let f = new Foo();

Anything else?

This works in older versions of Wing (0.50.0)

Wing Version

0.57.5

Node.js Version

20.9.0

Platform(s)

MacOS

Community Notes

eladb commented 9 months ago

We need to start diving into these unqualified lifts.

The array/map case is another very limiting factor:

let buckets = [b1,b2,b3];

inflight () => {
  for b in buckets {
    b.put("data", "bang");
  }
};

Oh I wish so much I could do this!

@yoav-steinberg πŸ™

Chriscbr commented 9 months ago

Since we have lazy lifting working, an example like that should also work if you used a MutArray, which would be neat:

let buckets = MutArray [b1,b2,b3];

inflight () => {
  for b in buckets {
    b.put("data", "bang");
  }
};

buckets.push(b4);
Chriscbr commented 9 months ago

Added a workaround to the issue

Chriscbr commented 9 months ago

Ideas from an offline discussion - perhaps the compiler can emit more granular emission for these kinds of cases in the SDK:

// wing
let maybeStr: str? = nil;
let maybeArr = Array<str?>[nil, "a"];
let bucket: cloud.Bucket? = nil;
let buckets = Array<cloud.Bucket>[new cloud.Bucket() as "bucket"];

new cloud.Function(inflight () => {
  log(maybeStr!);

  let i = 0;
  log(maybeArr.at(i)!);

  bucket!.put("key", "value");

  if let b1 = bucket {
    b.list("");
  }

  for b2 in buckets {
    b2.put("key", "value");
  }
});

producing these permissions

get _liftMap() {
  return ({
    "handle": [
      [maybeArr, ["at"]],
      [maybeStr, []],
      [bucket, ["unwrap:put", "unwrap:list"]],
      [buckets, ["each:put"]],
    ],
    "$inflight_init": [
    ],
  });
}