feat: Return type annotations #53

Merged
glen merged 15 commits from return_types into main 2022-08-30 19:36:44 +00:00
2 changed files with 39 additions and 38 deletions
Showing only changes of commit 95f6ccc5a0 - Show all commits

View File

@ -2,7 +2,7 @@
import typed from 'typed-function' import typed from 'typed-function'
import {makeChain} from './Chain.mjs' import {makeChain} from './Chain.mjs'
import {dependencyExtractor, generateTypeExtractor} from './extractors.mjs' import {dependencyExtractor, generateTypeExtractor} from './extractors.mjs'
import {R_, isReturnAnnotated} from './returns.mjs' import R_ from './returns.mjs'
import {typeListOfSignature, typesOfSignature, subsetOfKeys} from './utils.mjs' import {typeListOfSignature, typesOfSignature, subsetOfKeys} from './utils.mjs'
const anySpec = {} // fixed dummy specification of 'any' type const anySpec = {} // fixed dummy specification of 'any' type
@ -693,7 +693,7 @@ export default class PocomathInstance {
} }
/* Now build the catchall implementation */ /* Now build the catchall implementation */
const self = this const self = this
/* For return-type annotation, we will have to fix this to /* For return type annotation, we may have to fix this to
propagate the return type. At the moment we are just bagging propagate the return type. At the moment we are just bagging
*/ */
const patch = (refs) => (...args) => { const patch = (refs) => (...args) => {
@ -815,12 +815,9 @@ export default class PocomathInstance {
} }
} }
// Finally ready to make the call. // Finally ready to make the call.
let returnSpec = behavior.does(innerRefs) const implementation = behavior.does(innerRefs)
if (isReturnAnnotated(returnSpec)) { // Could do something with return type information here
// for now just drop return type information return implementation(...args)
returnSpec = returnSpec.via
}
return returnSpec(...args)
} }
// The actual uses value needs to be a set: // The actual uses value needs to be a set:
const outerUses = new Set(Object.values(simplifiedUses)) const outerUses = new Set(Object.values(simplifiedUses))
@ -862,12 +859,9 @@ export default class PocomathInstance {
_addTFimplementation(imps, signature, behavior) { _addTFimplementation(imps, signature, behavior) {
const {uses, does} = behavior const {uses, does} = behavior
if (uses.length === 0) { if (uses.length === 0) {
let returnSpec = does() const implementation = does()
if (isReturnAnnotated(returnSpec)) { // could do something with return type information here
// for now just dump the return information imps[signature] = implementation
returnSpec = returnSpec.via
}
imps[signature] = returnSpec
return return
} }
const refs = {} const refs = {}
@ -927,13 +921,9 @@ export default class PocomathInstance {
if (full_self_referential) { if (full_self_referential) {
imps[signature] = this._typed.referToSelf(self => { imps[signature] = this._typed.referToSelf(self => {
refs.self = self refs.self = self
let returnSpec = does(refs) const implementation = does(refs)
if (isReturnAnnotated(returnSpec)) { // What are we going to do with the return type info in here?
// What are we going to do with the return type info in here? return implementation
// Anyhow, drop it for now
returnSpec = returnSpec.via
}
return returnSpec
}) })
return return
} }
@ -953,12 +943,9 @@ export default class PocomathInstance {
} }
return return
} }
let returnSpec = does(refs) const implementation = does(refs)
if (isReturnAnnotated(returnSpec)) { // could do something with return type information here
// drop return type for now imps[signature] = implementation
returnSpec = returnSpec.via
}
imps[signature] = returnSpec
} }
_correctPartialSelfRefs(name, imps) { _correctPartialSelfRefs(name, imps) {
@ -993,13 +980,9 @@ export default class PocomathInstance {
for (let i = 0; i < part_self_references.length; ++i) { for (let i = 0; i < part_self_references.length; ++i) {
refs[`self(${part_self_references[i]})`] = impls[i] refs[`self(${part_self_references[i]})`] = impls[i]
} }
let returnSpec = does(refs) const implementation = does(refs)
if (isReturnAnnotated(returnSpec)) { // What will we do with the return type info in here?
// What will we do with the return type info in here? return implementation
// anyhow, drop it for now
returnSpec = returnSpec.via
}
return returnSpec
} }
) )
} }

View File

@ -1,10 +1,28 @@
/* Annotate a function with its return type */ /* Annotate a function with its return type */
export function R_(type, fn) {
return {returns: type, via: fn} /* Unfortunately JavaScript is missing a way to cleanly clone a function
* object, see https://stackoverflow.com/questions/1833588
*/
const clonedFrom = Symbol('the original function this one was cloned from')
function cloneFunction(fn) {
const behavior = fn[clonedFrom] || fn // don't nest clones
const theClone = function () { return behavior.apply(this, arguments) }
Object.assign(theClone, fn)
theClone[clonedFrom] = body
Object.defineProperty(
theClone, 'name', {value: fn.name, configurable: true })
return theClone
} }
export function isReturnAnnotated(x) { export function R_(type, fn) {
return x && typeof x === 'object' && 'returns' in x && 'via' in x if ('returns' in fn) fn = cloneFunction(fn)
fn.returns = type
return fn
}
export function returnTypeOf(fn) {
return fn.returns || 'any'
} }
export default R_ export default R_