Skip to content

Commit

Permalink
Merge of #3468
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jul 20, 2023
2 parents ce24a6a + 77c979b commit 34bff8e
Show file tree
Hide file tree
Showing 17 changed files with 1,196 additions and 124 deletions.
62 changes: 62 additions & 0 deletions examples/tests/invalid/super_call.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
class A {
method() {
// Acccess super with no base class (in case of preflight there's actually an implicit base class, `std.Resource`, we need to ignore)
super.method();
//^^^^^^ Cannot call super method because class A has no parent
}
}

inflight class InflightA {
method() {
// Access super with no base class
super.method();
//^^^^^^ Cannot call super method because class A has no parent
}
}

class B extends A {
child_method() {
// Access child method through super
super.child_method();
//^^^^^^^^^^^^ super class "A" does not have a method named "child_method"
}

static static_method() {
// super doesn't make sense in static context
super.method();
//^^^^^ Cannot call super method inside of a static method
}
}

// super doesn't make sense in global context
super.do();
//^^ "super" can only be used inside of classes


// Verify correct error message when inflight closure tries to access super (this isn't suported yet see: https://github.com/winglang/wing/issues/3474)
// Once it is, this test should be moved to "valid"
class BaseClass {
inflight m1(): str {
return "base inflight m1";
}
}

bring cloud;
let q = new cloud.Queue();
class ExtendedClass extends BaseClass {
inflight m1(): str {
return "extended inflight m1";
}
get_func(): cloud.Function {
let inflight_closure = inflight (s:str): str => {
return "this: ${this.m1()}, super: ${super.m1()}";
//^^ `super` calls inside inflight closures not supported yet, see: https://github.com/winglang/wing/issues/3474
};
return new cloud.Function(inflight_closure);
}
}
// TODO: uncomment and move to valid tests once this: https://github.com/winglang/wing/issues/3474 is fixed
// let y = new ExtendedClass().get_func();
// test "inflight closure accesses super" {
// assert(y.invoke("") == "this: extended inflight m1, super: base inflight m1");
// }
72 changes: 72 additions & 0 deletions examples/tests/valid/super_call.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
class A {
message: str;

init() {
this.message = "A message from your ancestor";
}
}

class B extends A {
description(): str {
return "B";
}
}

class C extends B {
description(): str {
return "C extends ${super.description()}";
}
}

// This class has no `description` method, so it inherits the one from `B`.
class D extends C {
}

class E extends D {
description(): str {
return "E extends ${super.description()}";
}
}

let e = new E();
// Make sure super calls work and skip anything in the inheritance chain that doesn't have the method
assert(e.description() == "E extends C extends B");

inflight class InflightA {
description(): str {
return "InflightA";
}
}

// Test super calls on inflight classes
inflight class InflightB extends InflightA {
description(): str {
return "InflightB extends ${super.description()}";
}
}

test "super call inflight" {
let b = new InflightB();
assert(b.description() == "InflightB extends InflightA");
}

// Test correct binding when calling a super method
bring cloud;
let b = new cloud.Bucket();
class BaseClass {
inflight do(): str {
return b.get("k"); // BaseClass class required read acceess to b
}
}

class ExtendedClass extends BaseClass {
inflight do(): str {
b.put("k", "value"); // This should require write access to b
return super.do(); // We expect to add binding permissions based on what `super.do()` requires (read)
}
}

let extended = new ExtendedClass();
test "super call sets binding permissions" {
assert(extended.do() == "value");
}
12 changes: 3 additions & 9 deletions libs/tree-sitter-wing/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -380,20 +380,14 @@ module.exports = grammar({
compiler_dbg_panic: ($) => "😱",
compiler_dbg_env: ($) => seq("🗺️", optional(";")),

_callable_expression: ($) =>
choice(
$.nested_identifier,
$.identifier,
$.call,
$.parenthesized_expression
),

call: ($) =>
prec.left(
PREC.CALL,
seq(field("caller", $.expression), field("args", $.argument_list))
seq(field("caller", choice($.expression, $.super_call)), field("args", $.argument_list))
),

super_call: ($) => seq($._super, ".", field("method", $.identifier)),

argument_list: ($) =>
seq(
"(",
Expand Down
19 changes: 18 additions & 1 deletion libs/wingc/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ pub enum ExprKind {
},
Reference(Reference),
Call {
callee: Box<Expr>,
callee: CalleeKind,
arg_list: ArgList,
},
Unary {
Expand Down Expand Up @@ -557,6 +557,23 @@ pub enum ExprKind {
CompilerDebugPanic,
}

#[derive(Debug)]
pub enum CalleeKind {
/// The callee is any expression
Expr(Box<Expr>),
/// The callee is a method in our super class
SuperCall(Symbol),
}

impl Spanned for CalleeKind {
fn span(&self) -> WingSpan {
match self {
CalleeKind::Expr(e) => e.span.clone(),
CalleeKind::SuperCall(method) => method.span(),
}
}
}

#[derive(Debug)]
pub struct Expr {
/// An identifier that is unique among all expressions in the AST.
Expand Down
7 changes: 5 additions & 2 deletions libs/wingc/src/fold.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
ast::{
ArgList, CatchBlock, Class, ClassField, ElifBlock, Expr, ExprKind, FunctionBody, FunctionDefinition,
ArgList, CalleeKind, CatchBlock, Class, ClassField, ElifBlock, Expr, ExprKind, FunctionBody, FunctionDefinition,
FunctionParameter, FunctionSignature, Interface, InterpolatedString, InterpolatedStringPart, Literal, NewExpr,
Reference, Scope, Stmt, StmtKind, StructField, Symbol, TypeAnnotation, TypeAnnotationKind, UserDefinedType,
},
Expand Down Expand Up @@ -263,7 +263,10 @@ where
},
ExprKind::Reference(reference) => ExprKind::Reference(f.fold_reference(reference)),
ExprKind::Call { callee, arg_list } => ExprKind::Call {
callee: Box::new(f.fold_expr(*callee)),
callee: match callee {
CalleeKind::Expr(expr) => CalleeKind::Expr(Box::new(f.fold_expr(*expr))),
CalleeKind::SuperCall(method) => CalleeKind::SuperCall(f.fold_symbol(method)),
},
arg_list: f.fold_args(arg_list),
},
ExprKind::Unary { op, exp } => ExprKind::Unary {
Expand Down
Loading

0 comments on commit 34bff8e

Please sign in to comment.