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

Abstract abstract #10513

Merged
merged 6 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/context/display/displayToplevel.ml
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,9 @@ let collect ctx tk with_type sort =
| Some(c,tl) -> add (make_ci_literal "super" (tpair (TInst(c,tl)))) (Some "super")
| None -> ()
end
| FunMemberAbstract ->
let t = TInst(ctx.curclass,List.map snd ctx.curclass.cl_params) in
add (make_ci_literal "abstract" (tpair t)) (Some "abstract");
| _ ->
()
end;
Expand Down
3 changes: 2 additions & 1 deletion src/syntax/grammar.mly
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,7 @@ and expr = parser
| [< '(Kwd Final,p1); v = parse_var_decl true >] -> (EVars [v],p1)
| [< '(Const c,p); s >] -> expr_next (EConst c,p) s
| [< '(Kwd This,p); s >] -> expr_next (EConst (Ident "this"),p) s
| [< '(Kwd Abstract,p); s >] -> expr_next (EConst (Ident "abstract"),p) s
| [< '(Kwd True,p); s >] -> expr_next (EConst (Ident "true"),p) s
| [< '(Kwd False,p); s >] -> expr_next (EConst (Ident "false"),p) s
| [< '(Kwd Null,p); s >] -> expr_next (EConst (Ident "null"),p) s
Expand Down Expand Up @@ -1674,4 +1675,4 @@ let rec parse_macro_cond s =
cond
with e ->
parsing_macro_cond := false;
raise e
raise e
12 changes: 12 additions & 0 deletions src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@ let rec type_ident_raise ctx i p mode with_type =
AKExpr (get_this ctx p)
| (MCall _, KAbstractImpl _) | (MGet, _)-> AKExpr(get_this ctx p)
| _ -> AKNo i)
| "abstract" ->
begin match mode, ctx.curclass.cl_kind with
| MSet _, KAbstractImpl ab -> typing_error "Property 'abstract' is read-only" p;
| (MGet, KAbstractImpl ab)
| (MCall _, KAbstractImpl ab) ->
let tl = List.map snd ab.a_params in
let e = get_this ctx p in
let e = {e with etype = TAbstract (ab,tl)} in
AKExpr e
| _ ->
typing_error "Property 'abstract' is reserved and only available in abstracts" p
end
| "super" ->
let t = (match ctx.curclass.cl_super with
| None -> typing_error "Current class does not have a superclass" p
Expand Down
35 changes: 35 additions & 0 deletions tests/display/src/cases/Abstract.hx
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,39 @@ class Abstract extends DisplayTestCase {
eq(false, hasField(fields, "instanceField", "() -> Void"));
eq(true, hasField(fields, "staticField", "() -> Void"));
}

/**
abstract MyAbstract(String) {
public function new() this = "foo";

public function instanceField():Void {
{-1-}
}
static public function staticField():Void {
{-2-}
}
public function instanceField2():Void {
ab{-3-}stract;
}
}
abstract AbGeneric<T>(T) {
public function new(a:T) this = a;
public function foo() {
return ab{-4-}stract.bar();
}
public function bar() {
return th{-5-}is;
}
}
**/
function test3():Void {
final fields = toplevel(pos(1));
eq(true, hasToplevel(fields, "literal", "abstract"));
final fields = toplevel(pos(2));
eq(false, hasToplevel(fields, "literal", "abstract"));
// TODO: improve display hints
// eq("cases.MyAbstract", type(pos(3)));
// eq("cases.AbGeneric<cases.AbGeneric.T>", type(pos(4)));
eq("cases.AbGeneric.T", type(pos(5)));
}
}
7 changes: 7 additions & 0 deletions tests/misc/projects/Issue10482/Main.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Main {
static function main() {
abstract;
abstract();
abstract + 1;
}
}
2 changes: 2 additions & 0 deletions tests/misc/projects/Issue10482/compile-fail.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--main Main
--interp
3 changes: 3 additions & 0 deletions tests/misc/projects/Issue10482/compile-fail.hxml.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Main.hx:3: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
Main.hx:4: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
Main.hx:5: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
86 changes: 86 additions & 0 deletions tests/unit/src/unit/issues/Issue10482.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package unit.issues;

class Issue10482 extends Test {
function test() {
final ab = new MyAbstract(1);
final arr = ab.foo();
eq('plus 2', arr[0]);
eq("call", arr[1]);
eq("hi", arr[2]);

eq(1, ab.arr()[0].arr()[0].value());
eq("plus 3", ab + 3);
eq("call", ab());
eq("hi", ab.arr()[0].hi());

final ab = new MyInlineAbstract(1);
final arr = ab.foo();
eq('plus 2', arr[0]);
eq("call", arr[1]);
eq("hi", arr[2]);

eq(1, ab.arr()[0].arr()[0].value());
eq("plus 3", ab + 3);
eq("call", ab());
eq("hi", ab.arr()[0].hi());

final ab = new AbGeneric(1.5);
eq(1.5, ab.foo());
}
}

abstract MyAbstract(Int) {
public function new(a):Void this = a;

public function foo():Array<String> {
return [
abstract + 2,
abstract(),
abstract.hi()
];
}

public function hi() return "hi";

public function arr() return [abstract];

@:op(a()) function call() return "call";

@:op(a + b) function plus(b) return 'plus $b';

public function value():Int return this;
}

abstract MyInlineAbstract(Int) {
public inline function new(a):Void this = a;

public inline function foo():Array<String> {
return [
abstract + 2,
abstract(),
abstract.hi()
];
}

public function hi() return "hi";

public function arr() return [abstract];

@:op(a()) function call() return "call";

@:op(a + b) function plus(b) return 'plus $b';

public function value():Int return this;
}

abstract AbGeneric<T>(T) {
public function new(a:T):Void {
this = a;
}
public function foo() {
return abstract.bar();
}
public function bar() {
return this;
}
}