@@ -389,8 +389,8 @@ export class Compiler extends DiagnosticEmitter {
389389 lazyFunctions : Set < Function > = new Set ( ) ;
390390 /** Pending class-specific instanceof helpers. */
391391 pendingClassInstanceOf : Set < ClassPrototype > = new Set ( ) ;
392- /** Functions potentially involving a virtual call . */
393- virtualCalls : Set < Function > = new Set ( ) ;
392+ /** Virtually called stubs that may have overloads . */
393+ virtualStubs : Set < Function > = new Set ( ) ;
394394 /** Elements currently undergoing compilation. */
395395 pendingElements : Set < Element > = new Set ( ) ;
396396 /** Elements, that are module exports, already processed */
@@ -450,6 +450,7 @@ export class Compiler extends DiagnosticEmitter {
450450 var options = this . options ;
451451 var module = this . module ;
452452 var program = this . program ;
453+ var resolver = this . resolver ;
453454 var hasShadowStack = options . stackSize > 0 ; // implies runtime=incremental
454455
455456 // initialize lookup maps, built-ins, imports, exports, etc.
@@ -530,26 +531,37 @@ export class Compiler extends DiagnosticEmitter {
530531 compileClassInstanceOf ( this , prototype ) ;
531532 }
532533
533- // set up virtual lookup tables
534+ // set up virtual stubs
534535 var functionTable = this . functionTable ;
536+ var virtualStubs = this . virtualStubs ;
535537 for ( let i = 0 , k = functionTable . length ; i < k ; ++ i ) {
536538 let instance = functionTable [ i ] ;
537539 if ( instance . is ( CommonFlags . VIRTUAL ) ) {
538540 assert ( instance . is ( CommonFlags . INSTANCE ) ) ;
539- functionTable [ i ] = this . ensureVirtualStub ( instance ) ; // incl. varargs
540- this . finalizeVirtualStub ( instance ) ;
541+ functionTable [ i ] = this . ensureVirtualStub ( instance ) ; // includes varargs stub
541542 } else if ( instance . signature . requiredParameters < instance . signature . parameterTypes . length ) {
542543 functionTable [ i ] = this . ensureVarargsStub ( instance ) ;
543544 }
544545 }
545- var virtualCalls = this . virtualCalls ;
546- while ( virtualCalls . size ) {
547- // finalizing a stub may discover more virtual calls, so do this in a loop
548- for ( let _values = Set_values ( virtualCalls ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
546+ var virtualStubsSeen = new Set < Function > ( ) ;
547+ do {
548+ // virtual stubs and overloads have cross-dependencies on each other, in that compiling
549+ // either may discover the respective other. do this in a loop until no more are found.
550+ resolver . discoveredOverload = false ;
551+ for ( let _values = Set_values ( virtualStubs ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
549552 let instance = unchecked ( _values [ i ] ) ;
550- this . finalizeVirtualStub ( instance ) ;
551- virtualCalls . delete ( instance ) ;
553+ let overloadInstances = resolver . resolveOverloads ( instance ) ;
554+ if ( overloadInstances ) {
555+ for ( let i = 0 , k = overloadInstances . length ; i < k ; ++ i ) {
556+ this . compileFunction ( overloadInstances [ i ] ) ;
557+ }
558+ }
559+ virtualStubsSeen . add ( instance ) ;
552560 }
561+ } while ( virtualStubs . size > virtualStubsSeen . size || resolver . discoveredOverload ) ;
562+ virtualStubsSeen . clear ( ) ;
563+ for ( let _values = Set_values ( virtualStubs ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
564+ this . finalizeVirtualStub ( _values [ i ] ) ;
553565 }
554566
555567 // finalize runtime features
@@ -6949,7 +6961,7 @@ export class Compiler extends DiagnosticEmitter {
69496961 null ,
69506962 module . unreachable ( )
69516963 ) ;
6952- this . virtualCalls . add ( original ) ;
6964+ this . virtualStubs . add ( original ) ;
69536965 return stub ;
69546966 }
69556967
@@ -6958,11 +6970,7 @@ export class Compiler extends DiagnosticEmitter {
69586970 var stub = this . ensureVirtualStub ( instance ) ;
69596971 if ( stub . is ( CommonFlags . COMPILED ) ) return ;
69606972
6961- // Wouldn't be here if there wasn't at least one overload
6962- var overloadPrototypes = assert ( instance . prototype . overloads ) ;
6963-
69646973 assert ( instance . parent . kind == ElementKind . CLASS || instance . parent . kind == ElementKind . INTERFACE ) ;
6965- var parentClassInstance = < Class > instance . parent ;
69666974 var module = this . module ;
69676975 var usizeType = this . options . usizeType ;
69686976 var sizeTypeRef = usizeType . toRef ( ) ;
@@ -6986,106 +6994,65 @@ export class Compiler extends DiagnosticEmitter {
69866994 TypeRef . I32
69876995 )
69886996 ) ;
6989-
6990- // A method's `overloads` property contains its unbound overload prototypes
6991- // so we first have to find the concrete classes it became bound to, obtain
6992- // their bound prototypes and make sure these are resolved and compiled as
6993- // we are going to call them conditionally based on this's class id.
6994- for ( let _values = Set_values ( overloadPrototypes ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
6995- let unboundOverloadPrototype = _values [ i ] ;
6996- assert ( ! unboundOverloadPrototype . isBound ) ;
6997- let unboundOverloadParent = unboundOverloadPrototype . parent ;
6998- let isProperty = unboundOverloadParent . kind == ElementKind . PROPERTY_PROTOTYPE ;
6999- let classInstances : Map < string , Class > | null ;
7000- if ( isProperty ) {
7001- let propertyParent = ( < PropertyPrototype > unboundOverloadParent ) . parent ;
7002- assert ( propertyParent . kind == ElementKind . CLASS_PROTOTYPE ) ;
7003- classInstances = ( < ClassPrototype > propertyParent ) . instances ;
7004- } else {
7005- assert ( unboundOverloadParent . kind == ElementKind . CLASS_PROTOTYPE ) ;
7006- classInstances = ( < ClassPrototype > unboundOverloadParent ) . instances ;
7007- }
7008- if ( classInstances ) {
7009- for ( let _values = Map_values ( classInstances ) , j = 0 , l = _values . length ; j < l ; ++ j ) {
7010- let classInstance = _values [ j ] ;
7011- // Chcek if the parent class is a subtype of instance's class
7012- if ( ! classInstance . isAssignableTo ( parentClassInstance ) ) continue ;
7013- let overloadInstance : Function | null ;
7014- if ( isProperty ) {
7015- let boundProperty = assert ( classInstance . members ! . get ( unboundOverloadParent . name ) ) ;
7016- assert ( boundProperty . kind == ElementKind . PROPERTY_PROTOTYPE ) ;
7017- let boundPropertyInstance = this . resolver . resolveProperty ( < PropertyPrototype > boundProperty ) ;
7018- if ( ! boundPropertyInstance ) continue ;
7019- if ( instance . is ( CommonFlags . GET ) ) {
7020- overloadInstance = boundPropertyInstance . getterInstance ;
7021- } else {
7022- assert ( instance . is ( CommonFlags . SET ) ) ;
7023- overloadInstance = boundPropertyInstance . setterInstance ;
7024- }
7025- } else {
7026- let boundPrototype = assert ( classInstance . members ! . get ( unboundOverloadPrototype . name ) ) ;
7027- assert ( boundPrototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
7028- overloadInstance = this . resolver . resolveFunction ( < FunctionPrototype > boundPrototype , instance . typeArguments ) ;
7029- }
7030- if ( ! overloadInstance || ! this . compileFunction ( overloadInstance ) ) continue ;
7031- let overloadType = overloadInstance . type ;
7032- let originalType = instance . type ;
7033- if ( ! overloadType . isAssignableTo ( originalType ) ) {
7034- this . error (
7035- DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
7036- overloadInstance . identifierNode . range , overloadType . toString ( ) , originalType . toString ( )
7037- ) ;
7038- continue ;
7039- }
7040- // TODO: additional optional parameters are not permitted by `isAssignableTo` yet
7041- let overloadSignature = overloadInstance . signature ;
7042- let overloadParameterTypes = overloadSignature . parameterTypes ;
7043- let overloadNumParameters = overloadParameterTypes . length ;
7044- let paramExprs = new Array < ExpressionRef > ( 1 + overloadNumParameters ) ;
7045- paramExprs [ 0 ] = module . local_get ( 0 , sizeTypeRef ) ; // this
7046- for ( let n = 1 ; n <= numParameters ; ++ n ) {
7047- paramExprs [ n ] = module . local_get ( n , parameterTypes [ n - 1 ] . toRef ( ) ) ;
7048- }
7049- let needsVarargsStub = false ;
7050- for ( let n = numParameters ; n < overloadNumParameters ; ++ n ) {
7051- // TODO: inline constant initializers and skip varargs stub
7052- paramExprs [ 1 + n ] = this . makeZero ( overloadParameterTypes [ n ] , overloadInstance . declaration ) ;
7053- needsVarargsStub = true ;
7054- }
7055- let calledName = needsVarargsStub
7056- ? this . ensureVarargsStub ( overloadInstance ) . internalName
7057- : overloadInstance . internalName ;
7058- let returnTypeRef = overloadSignature . returnType . toRef ( ) ;
7059- let stmts = new Array < ExpressionRef > ( ) ;
7060- if ( needsVarargsStub ) {
7061- // Safe to prepend since paramExprs are local.get's
7062- stmts . push ( module . global_set ( this . ensureArgumentsLength ( ) , module . i32 ( numParameters ) ) ) ;
7063- }
7064- if ( returnType == Type . void ) {
7065- stmts . push (
6997+ var overloadInstances = this . resolver . resolveOverloads ( instance ) ;
6998+ if ( overloadInstances ) {
6999+ for ( let i = 0 , k = overloadInstances . length ; i < k ; ++ i ) {
7000+ let overloadInstance = overloadInstances [ i ] ;
7001+ if ( ! overloadInstance . is ( CommonFlags . COMPILED ) ) continue ; // errored
7002+ let overloadType = overloadInstance . type ;
7003+ let originalType = instance . type ;
7004+ if ( ! overloadType . isAssignableTo ( originalType ) ) {
7005+ this . error (
7006+ DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
7007+ overloadInstance . identifierNode . range , overloadType . toString ( ) , originalType . toString ( )
7008+ ) ;
7009+ continue ;
7010+ }
7011+ // TODO: additional optional parameters are not permitted by `isAssignableTo` yet
7012+ let overloadSignature = overloadInstance . signature ;
7013+ let overloadParameterTypes = overloadSignature . parameterTypes ;
7014+ let overloadNumParameters = overloadParameterTypes . length ;
7015+ let paramExprs = new Array < ExpressionRef > ( 1 + overloadNumParameters ) ;
7016+ paramExprs [ 0 ] = module . local_get ( 0 , sizeTypeRef ) ; // this
7017+ for ( let n = 1 ; n <= numParameters ; ++ n ) {
7018+ paramExprs [ n ] = module . local_get ( n , parameterTypes [ n - 1 ] . toRef ( ) ) ;
7019+ }
7020+ let needsVarargsStub = false ;
7021+ for ( let n = numParameters ; n < overloadNumParameters ; ++ n ) {
7022+ // TODO: inline constant initializers and skip varargs stub
7023+ paramExprs [ 1 + n ] = this . makeZero ( overloadParameterTypes [ n ] , overloadInstance . declaration ) ;
7024+ needsVarargsStub = true ;
7025+ }
7026+ let calledName = needsVarargsStub
7027+ ? this . ensureVarargsStub ( overloadInstance ) . internalName
7028+ : overloadInstance . internalName ;
7029+ let returnTypeRef = overloadSignature . returnType . toRef ( ) ;
7030+ let stmts = new Array < ExpressionRef > ( ) ;
7031+ if ( needsVarargsStub ) {
7032+ // Safe to prepend since paramExprs are local.get's
7033+ stmts . push ( module . global_set ( this . ensureArgumentsLength ( ) , module . i32 ( numParameters ) ) ) ;
7034+ }
7035+ if ( returnType == Type . void ) {
7036+ stmts . push (
7037+ module . call ( calledName , paramExprs , returnTypeRef )
7038+ ) ;
7039+ stmts . push (
7040+ module . return ( )
7041+ ) ;
7042+ } else {
7043+ stmts . push (
7044+ module . return (
70667045 module . call ( calledName , paramExprs , returnTypeRef )
7067- ) ;
7068- stmts . push (
7069- module . return ( )
7070- ) ;
7071- } else {
7072- stmts . push (
7073- module . return (
7074- module . call ( calledName , paramExprs , returnTypeRef )
7075- )
7076- ) ;
7077- }
7078- builder . addCase ( classInstance . id , stmts ) ;
7079- // Also alias each extendee inheriting this exact overload
7080- let extendees = classInstance . getAllExtendees (
7081- isProperty
7082- ? unboundOverloadParent . name
7083- : instance . prototype . name
7046+ )
70847047 ) ;
7085- for ( let _values = Set_values ( extendees ) , a = 0 , b = _values . length ; a < b ; ++ a ) {
7086- let extendee = _values [ a ] ;
7087- builder . addCase ( extendee . id , stmts ) ;
7088- }
7048+ }
7049+ let classInstance = assert ( overloadInstance . getClassOrInterface ( ) ) ;
7050+ builder . addCase ( classInstance . id , stmts ) ;
7051+ // Also alias each extendee inheriting this exact overload
7052+ let extendees = classInstance . getAllExtendees ( instance . declaration . name . text ) ; // without get:/set:
7053+ for ( let _values = Set_values ( extendees ) , a = 0 , b = _values . length ; a < b ; ++ a ) {
7054+ let extendee = _values [ a ] ;
7055+ builder . addCase ( extendee . id , stmts ) ;
70897056 }
70907057 }
70917058 }
0 commit comments