Skip to content

Instantly share code, notes, and snippets.

@jasononeil
Created February 19, 2014 05:11
Show Gist options
  • Save jasononeil/9086395 to your computer and use it in GitHub Desktop.
Save jasononeil/9086395 to your computer and use it in GitHub Desktop.
Method used in a macro to figure out the return type of a member method. Uses tink_macro
/**
Figure out return type of function.
Will first to check if it is explicitly defined.
If not, it attempts to set the function up as a local function expression (EFunction), and then use `Context.typeof( fnExpr )` to evaluate the type.
Will generate a compiler error if member was not a method or method type could not be determined.
**/
static function figureOutReturnTypeOfMemberMethod( member:Member ) {
switch member.getFunction() {
case Success( fn ):
if ( fn.ret!=null ) {
return fn.ret;
}
else {
try {
var fnExpr:Expr = { expr: EFunction(null,fn), pos: member.pos };
var args:Array<Expr> = [ for (i in 0...fn.args.length) macro null ];
var callExpr = macro $fnExpr( $a{args} );
var t = Context.typeof( callExpr );
return t.toComplexType();
}
catch (e:Dynamic) {
Context.error( 'Failed to get type of method ${member.name}: '+e, member.pos );
}
}
case Failure( err ):
Context.error('figureOutReturnTypeOfMemberMethod expected a method, but got some other kind of field: '+err.message, err.pos );
}
return null;
}
@jasononeil
Copy link
Author

Please note in the end this didn't work. Basically Context.parse() would go through each expression in the function body, and for simple stuff, it was fine. Once you started including links to outside variables and classes, things got difficult.

I tried to use tink's expr.typeof( [ variables in context ] ) trick, and was able to fake the current fields and the super class, but any references to a 3rd party class had no guarantee of being compiled yet, and so their fields were not accessible, resulting in typeof failing with errors like Future has no field sync, when Future most certainly did have a field called sync.

In the end I've had to settle for a solution where I use Context.onGenerate to provide a callback after all the typing is done, but at this point, it's too late to change any expressions, so I have to settle for writing metadata, and then at runtime, read that metadata and act accordingly.

It's a little disappointing, but at least it will work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment