@@ -331,10 +331,15 @@ class SyntheticTypeConverter {
331331 // Currently it has no state (other than recording that nameContext is not
332332 // undefined) and is just factored away from converter to keep things tidier.
333333 converter : Converter ;
334- nameContext : string [ ] ;
335- constructor ( converter : Converter , nameContext : string [ ] ) {
334+ constructor ( converter : Converter ) {
336335 this . converter = converter ;
337- this . nameContext = nameContext ;
336+ }
337+ get nameContext ( ) : string [ ] {
338+ const ctx = this . converter . nameContext ;
339+ if ( ! ctx ) {
340+ throw new Error ( "Should not happen" ) ;
341+ }
342+ return ctx ;
338343 }
339344
340345 hasWork ( base : TypeNode , modifiers : Modifier ) {
@@ -657,10 +662,7 @@ export class Converter {
657662 if ( ! typeRoot ) {
658663 return undefined ;
659664 }
660- return new SyntheticTypeConverter (
661- this ,
662- this . nameContext ,
663- ) . classifiedTypeToIr ( typeRoot ) ;
665+ return new SyntheticTypeConverter ( this ) . classifiedTypeToIr ( typeRoot ) ;
664666 }
665667
666668 typeToIR (
@@ -751,13 +753,27 @@ export class Converter {
751753
752754 const pyParams : ParamIR [ ] = [ ] ;
753755 let spreadParam : ParamIR | undefined ;
754- for ( const param of decl . getParameters ( ) ) {
756+ const params = decl . getParameters ( ) ;
757+ for ( let idx = 0 ; idx < params . length ; idx ++ ) {
758+ const param = params [ idx ] ;
755759 const spread = ! ! param . getDotDotDotToken ( ) ;
756760 const optional = ! ! param . hasQuestionToken ( ) ;
757761 const name = param . getName ( ) ;
758- this . pushNameContext ( name ) ;
759- const type = this . typeToIR ( param . getTypeNode ( ) ! , optional ) ;
760- this . popNameContext ( ) ;
762+ const isValidPythonIdentifier = / ^ [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ ] * $ / . test ( name ) ;
763+ const oldNameContext = this . nameContext ?. slice ( ) ;
764+ const paramType = param . getTypeNode ( ) ! ;
765+ const isLast = idx === params . length - 1 ;
766+ if ( isLast && Node . isTypeLiteral ( paramType ) ) {
767+ // If it's the last argument and the type is a type literal, we'll
768+ // destructure it so don't make a type.
769+ this . nameContext = undefined ;
770+ } else if ( isValidPythonIdentifier ) {
771+ this . pushNameContext ( name ) ;
772+ } else {
773+ this . nameContext = undefined ;
774+ }
775+ const type = this . typeToIR ( paramType , optional ) ;
776+ this . nameContext = oldNameContext ;
761777 const pyParam : ParamIR = {
762778 name,
763779 type,
@@ -934,7 +950,10 @@ export class Converter {
934950
935951 funcDeclsToIR ( name : string , decls : FunctionDeclaration [ ] ) : CallableIR {
936952 const astSigs = decls . map ( ( x ) => x . getSignature ( ) ) ;
953+ const origNameContext = this . nameContext ;
954+ this . nameContext ??= [ ] ;
937955 const result = this . callableToIR ( name , astSigs , false ) ;
956+ this . nameContext = origNameContext ;
938957 return result ;
939958 }
940959
0 commit comments