Try to be smarter about when bouncing initialization.

This commit is contained in:
Juraj Kirchheim
2020-01-06 14:35:26 +01:00
parent b48b300cbc
commit a101378a4c

View File

@@ -25,20 +25,20 @@ class Constructor {
var owner:ClassBuilder; var owner:ClassBuilder;
var meta:Metadata; var meta:Metadata;
public var isPublic:Null<Bool>; public var isPublic:Null<Bool>;
public function new(owner:ClassBuilder, f:Function, ?isPublic:Null<Bool> = null, ?pos:Position, ?meta:Metadata) { public function new(owner:ClassBuilder, f:Function, ?isPublic:Null<Bool> = null, ?pos:Position, ?meta:Metadata) {
this.nuStatements = []; this.nuStatements = [];
this.owner = owner; this.owner = owner;
this.isPublic = isPublic; this.isPublic = isPublic;
this.pos = pos.sanitize(); this.pos = pos.sanitize();
this.onGenerateHooks = []; this.onGenerateHooks = [];
this.args = []; this.args = [];
this.beforeArgs = []; this.beforeArgs = [];
this.afterArgs = []; this.afterArgs = [];
this.meta = meta; this.meta = meta;
this.oldStatements = this.oldStatements =
if (f == null) []; if (f == null) [];
else { else {
for (i in 0...f.args.length) { for (i in 0...f.args.length) {
@@ -49,15 +49,15 @@ class Constructor {
} }
beforeArgs.push(a); beforeArgs.push(a);
} }
if (f.expr == null) []; if (f.expr == null) [];
else else
switch (f.expr.expr) { switch (f.expr.expr) {
case EBlock(exprs): exprs; case EBlock(exprs): exprs;
default: oldStatements = [f.expr]; default: oldStatements = [f.expr];
} }
} }
superCall = superCall =
if (oldStatements.length == 0) [].toBlock(); if (oldStatements.length == 0) [].toBlock();
else switch oldStatements[0] { else switch oldStatements[0] {
case macro super($a{_}): oldStatements.shift(); case macro super($a{_}): oldStatements.shift();
@@ -68,43 +68,69 @@ class Constructor {
public function getArgList():Array<FunctionArg> public function getArgList():Array<FunctionArg>
return beforeArgs.concat(args).concat(afterArgs); return beforeArgs.concat(args).concat(afterArgs);
public function addStatement(e:Expr, ?prepend) public function addStatement(e:Expr, ?prepend)
if (prepend) if (prepend)
this.nuStatements.unshift(e) this.nuStatements.unshift(e)
else else
this.nuStatements.push(e); this.nuStatements.push(e);
public function addArg(name:String, ?t:ComplexType, ?e:Expr, ?opt = false) public function addArg(name:String, ?t:ComplexType, ?e:Expr, ?opt = false)
args.push( { name : name, opt : opt || e != null, type : t, value: e } ); args.push( { name : name, opt : opt || e != null, type : t, value: e } );
public function init(name:String, pos:Position, with:FieldInit, ?options:{ ?prepend:Bool, ?bypass:Bool }) { public function init(name:String, pos:Position, with:FieldInit, ?options:{ ?prepend:Bool, ?bypass:Bool }) {
if (options == null) if (options == null)
options = {}; options = {};
var e = var e =
switch with { switch with {
case Arg(t, noPublish): case Arg(t, noPublish):
if (noPublish != true) if (noPublish != true)
publish(); publish();
args.push( { name : name, opt : false, type : t } ); args.push( { name : name, opt : false, type : t } );
name.resolve(pos); name.resolve(pos);
case OptArg(e, t, noPublish): case OptArg(e, t, noPublish):
if (noPublish != true) if (noPublish != true)
publish(); publish();
args.push( { name : name, opt : true, type : t, value: e } ); args.push( { name : name, opt : true, type : t, value: e } );
name.resolve(pos); name.resolve(pos);
case Value(e): e; case Value(e): e;
} }
var tmp = MacroApi.tempName(); var tmp = MacroApi.tempName();
var member = owner.memberByName(name).sure(); var member = owner.memberByName(name).sure();
if (options.bypass && member.kind.match(FProp(_, 'never' | 'set', _, _))) {
member.addMeta(':isVar');
var metaBypass = false;
var bypass = switch options.bypass {
case null:
switch member.kind {
case FProp(_, 'default' | 'null', _):
false;
#if haxe4
case FProp('default', 'never', _):
member.isFinal = true;
case FProp(_, 'set', _):
member.addMeta(':isVar');
metaBypass = true;
#end
case FProp(_):
true;
case FFun(_):
pos.error('cannot rebind function');
default: false;
}
case v: v;
}
if (options.bypass && member.kind.match(FProp(_, 'never' | 'set', _, _))) {
member.addMeta(':isVar');
switch member.kind {
case FProp(get, set, _):
member.pos.warning('$get,$set');
default:
}
addStatement((function () { addStatement((function () {
var fields = [for (f in (macro this).typeof().sure().getClass().fields.get()) f.name => f]; var fields = [for (f in (macro this).typeof().sure().getClass().fields.get()) f.name => f];
function setDirectly(t:TypedExpr) { function setDirectly(t:TypedExpr) {
var direct = null; var direct = null;
function seek(t:TypedExpr) { function seek(t:TypedExpr) {
@@ -112,15 +138,15 @@ class Constructor {
case TField({ expr: TConst(TThis) }, FInstance(_, _, f)) if (f.get().name == name): direct = t; case TField({ expr: TConst(TThis) }, FInstance(_, _, f)) if (f.get().name == name): direct = t;
default: t.iter(seek); default: t.iter(seek);
} }
} }
seek(t); seek(t);
if (direct == null) pos.error('nope'); if (direct == null) pos.error('nope');
var direct = Context.storeTypedExpr(direct); var direct = Context.storeTypedExpr(direct);
return macro @:pos(pos) $direct = $e; return macro @:pos(pos) $direct = $e;
} }
return switch fields[name] { return switch fields[name] {
case null: case null:
pos.error('this direct initialization causes the compiler to do really weird things'); pos.error('this direct initialization causes the compiler to do really weird things');
case f: case f:
switch f.kind { switch f.kind {
@@ -138,24 +164,30 @@ class Constructor {
pos.error('not implemented'); pos.error('not implemented');
} }
} }
}).bounce(), options.prepend); }).bounce(), options.prepend);
} }
else else
addStatement(macro @:pos(pos) this.$name = $e, options.prepend); addStatement(
if (metaBypass)
macro @:pos(pos) @:bypassAccessor this.$name = $e
else
macro @:pos(pos) this.$name = $e,
options.prepend
);
} }
public inline function publish() public inline function publish()
if (isPublic == null) if (isPublic == null)
isPublic = true; isPublic = true;
function toBlock() function toBlock()
return [superCall] return [superCall]
.concat(nuStatements) .concat(nuStatements)
.concat(oldStatements) .concat(oldStatements)
.toBlock(pos); .toBlock(pos);
public function onGenerate(hook) public function onGenerate(hook)
this.onGenerateHooks.push(hook); this.onGenerateHooks.push(hook);
public function toHaxe():Field { public function toHaxe():Field {
var f:Function = { var f:Function = {
args: this.beforeArgs.concat(this.args).concat(this.afterArgs), args: this.beforeArgs.concat(this.args).concat(this.afterArgs),