@flighthq/tool-compiler 0.5.1-edge.1687.b63c819
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +74 -0
- package/dist/packages/compiler-ambient/src/compilerAmbientSurface.d.ts +3 -0
- package/dist/packages/compiler-ambient/src/compilerAmbientSurface.d.ts.map +1 -0
- package/dist/packages/compiler-ambient/src/compilerAmbientSurface.js +564 -0
- package/dist/packages/compiler-ambient/src/compilerAmbientSurface.js.map +1 -0
- package/dist/packages/compiler-ambient/src/index.d.ts +2 -0
- package/dist/packages/compiler-ambient/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-ambient/src/index.js +2 -0
- package/dist/packages/compiler-ambient/src/index.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppAmbientMemberBinding.d.ts +3 -0
- package/dist/packages/compiler-backend-cpp/src/cppAmbientMemberBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppAmbientMemberBinding.js +146 -0
- package/dist/packages/compiler-backend-cpp/src/cppAmbientMemberBinding.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppBindingTypeInference.d.ts +3 -0
- package/dist/packages/compiler-backend-cpp/src/cppBindingTypeInference.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppBindingTypeInference.js +197 -0
- package/dist/packages/compiler-backend-cpp/src/cppBindingTypeInference.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCallableSignatureAbi.d.ts +8 -0
- package/dist/packages/compiler-backend-cpp/src/cppCallableSignatureAbi.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCallableSignatureAbi.js +9 -0
- package/dist/packages/compiler-backend-cpp/src/cppCallableSignatureAbi.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppClosureCapturePlan.d.ts +3 -0
- package/dist/packages/compiler-backend-cpp/src/cppClosureCapturePlan.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppClosureCapturePlan.js +109 -0
- package/dist/packages/compiler-backend-cpp/src/cppClosureCapturePlan.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerBackend.d.ts +4 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerBackend.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerBackend.js +16568 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerBackend.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerIdentity.d.ts +7 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerIdentity.js +176 -0
- package/dist/packages/compiler-backend-cpp/src/cppCompilerIdentity.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppReferenceRepresentationPlan.d.ts +7 -0
- package/dist/packages/compiler-backend-cpp/src/cppReferenceRepresentationPlan.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppReferenceRepresentationPlan.js +1514 -0
- package/dist/packages/compiler-backend-cpp/src/cppReferenceRepresentationPlan.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppRuntimeExternalSymbolBinding.d.ts +44 -0
- package/dist/packages/compiler-backend-cpp/src/cppRuntimeExternalSymbolBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppRuntimeExternalSymbolBinding.js +1060 -0
- package/dist/packages/compiler-backend-cpp/src/cppRuntimeExternalSymbolBinding.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppTupleRepresentation.d.ts +3 -0
- package/dist/packages/compiler-backend-cpp/src/cppTupleRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppTupleRepresentation.js +13 -0
- package/dist/packages/compiler-backend-cpp/src/cppTupleRepresentation.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppUnionRepresentationPlan.d.ts +66 -0
- package/dist/packages/compiler-backend-cpp/src/cppUnionRepresentationPlan.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/cppUnionRepresentationPlan.js +196 -0
- package/dist/packages/compiler-backend-cpp/src/cppUnionRepresentationPlan.js.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/index.d.ts +6 -0
- package/dist/packages/compiler-backend-cpp/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-backend-cpp/src/index.js +6 -0
- package/dist/packages/compiler-backend-cpp/src/index.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeAmbientMemberBinding.d.ts +4 -0
- package/dist/packages/compiler-backend-hx/src/haxeAmbientMemberBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeAmbientMemberBinding.js +160 -0
- package/dist/packages/compiler-backend-hx/src/haxeAmbientMemberBinding.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeAsyncIterationLowering.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeAsyncIterationLowering.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeAsyncIterationLowering.js +129 -0
- package/dist/packages/compiler-backend-hx/src/haxeAsyncIterationLowering.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerBackend.d.ts +5 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerBackend.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerBackend.js +5172 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerBackend.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerEmittedSourceSyntax.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerEmittedSourceSyntax.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerEmittedSourceSyntax.js +8 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerEmittedSourceSyntax.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerIdentity.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerIdentity.js +51 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerIdentity.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerTargetCompilationSmoke.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerTargetCompilationSmoke.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerTargetCompilationSmoke.js +8 -0
- package/dist/packages/compiler-backend-hx/src/haxeCompilerTargetCompilationSmoke.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeExternEmission.d.ts +40 -0
- package/dist/packages/compiler-backend-hx/src/haxeExternEmission.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeExternEmission.js +968 -0
- package/dist/packages/compiler-backend-hx/src/haxeExternEmission.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeAbiManifest.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeAbiManifest.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeAbiManifest.js +53 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeAbiManifest.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalConstructorAbi.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalConstructorAbi.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalConstructorAbi.js +64 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalConstructorAbi.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalSymbolBinding.d.ts +8 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalSymbolBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalSymbolBinding.js +803 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeExternalSymbolBinding.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeTaskCapability.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeTaskCapability.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeTaskCapability.js +66 -0
- package/dist/packages/compiler-backend-hx/src/haxeRuntimeTaskCapability.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskEmission.d.ts +3 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskEmission.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskEmission.js +361 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskEmission.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskLowering.d.ts +4 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskLowering.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskLowering.js +265 -0
- package/dist/packages/compiler-backend-hx/src/haxeTaskLowering.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTypeEmission.d.ts +16 -0
- package/dist/packages/compiler-backend-hx/src/haxeTypeEmission.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/haxeTypeEmission.js +134 -0
- package/dist/packages/compiler-backend-hx/src/haxeTypeEmission.js.map +1 -0
- package/dist/packages/compiler-backend-hx/src/index.d.ts +13 -0
- package/dist/packages/compiler-backend-hx/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-backend-hx/src/index.js +13 -0
- package/dist/packages/compiler-backend-hx/src/index.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/index.d.ts +8 -0
- package/dist/packages/compiler-backend-rs/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/index.js +8 -0
- package/dist/packages/compiler-backend-rs/src/index.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustAmbientMemberBinding.d.ts +3 -0
- package/dist/packages/compiler-backend-rs/src/rustAmbientMemberBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustAmbientMemberBinding.js +99 -0
- package/dist/packages/compiler-backend-rs/src/rustAmbientMemberBinding.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerBackend.d.ts +5 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerBackend.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerBackend.js +4555 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerBackend.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerEmittedSourceSyntax.d.ts +3 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerEmittedSourceSyntax.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerEmittedSourceSyntax.js +8 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerEmittedSourceSyntax.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerIdentity.d.ts +4 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerIdentity.js +113 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerIdentity.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerTargetCompilationSmoke.d.ts +3 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerTargetCompilationSmoke.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerTargetCompilationSmoke.js +8 -0
- package/dist/packages/compiler-backend-rs/src/rustCompilerTargetCompilationSmoke.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustOwnershipEvidence.d.ts +5 -0
- package/dist/packages/compiler-backend-rs/src/rustOwnershipEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustOwnershipEvidence.js +345 -0
- package/dist/packages/compiler-backend-rs/src/rustOwnershipEvidence.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalConstructorAbi.d.ts +3 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalConstructorAbi.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalConstructorAbi.js +38 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalConstructorAbi.js.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalSymbolBinding.d.ts +6 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalSymbolBinding.d.ts.map +1 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalSymbolBinding.js +301 -0
- package/dist/packages/compiler-backend-rs/src/rustRuntimeExternalSymbolBinding.js.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerPortablePath.d.ts +2 -0
- package/dist/packages/compiler-canonical-form/src/compilerPortablePath.d.ts.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerPortablePath.js +4 -0
- package/dist/packages/compiler-canonical-form/src/compilerPortablePath.js.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerStructuralValue.d.ts +2 -0
- package/dist/packages/compiler-canonical-form/src/compilerStructuralValue.d.ts.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerStructuralValue.js +63 -0
- package/dist/packages/compiler-canonical-form/src/compilerStructuralValue.js.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerTextOrder.d.ts +2 -0
- package/dist/packages/compiler-canonical-form/src/compilerTextOrder.d.ts.map +1 -0
- package/dist/packages/compiler-canonical-form/src/compilerTextOrder.js +4 -0
- package/dist/packages/compiler-canonical-form/src/compilerTextOrder.js.map +1 -0
- package/dist/packages/compiler-canonical-form/src/index.d.ts +4 -0
- package/dist/packages/compiler-canonical-form/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-canonical-form/src/index.js +4 -0
- package/dist/packages/compiler-canonical-form/src/index.js.map +1 -0
- package/dist/packages/compiler-check/src/compilerPackageCheck.d.ts +9 -0
- package/dist/packages/compiler-check/src/compilerPackageCheck.d.ts.map +1 -0
- package/dist/packages/compiler-check/src/compilerPackageCheck.js +417 -0
- package/dist/packages/compiler-check/src/compilerPackageCheck.js.map +1 -0
- package/dist/packages/compiler-check/src/index.d.ts +2 -0
- package/dist/packages/compiler-check/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-check/src/index.js +2 -0
- package/dist/packages/compiler-check/src/index.js.map +1 -0
- package/dist/packages/compiler-closure/src/compilerClosureEvidence.d.ts +3 -0
- package/dist/packages/compiler-closure/src/compilerClosureEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-closure/src/compilerClosureEvidence.js +469 -0
- package/dist/packages/compiler-closure/src/compilerClosureEvidence.js.map +1 -0
- package/dist/packages/compiler-closure/src/index.d.ts +2 -0
- package/dist/packages/compiler-closure/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-closure/src/index.js +2 -0
- package/dist/packages/compiler-closure/src/index.js.map +1 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLine.d.ts +12 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLine.d.ts.map +1 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLine.js +549 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLine.js.map +1 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLineEntryPoint.d.ts +5 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLineEntryPoint.d.ts.map +1 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLineEntryPoint.js +134 -0
- package/dist/packages/compiler-command-line/src/compilerCommandLineEntryPoint.js.map +1 -0
- package/dist/packages/compiler-command-line/src/index.d.ts +3 -0
- package/dist/packages/compiler-command-line/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-command-line/src/index.js +3 -0
- package/dist/packages/compiler-command-line/src/index.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerAsyncTaskCompletion.d.ts +6 -0
- package/dist/packages/compiler-completion/src/compilerAsyncTaskCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerAsyncTaskCompletion.js +89 -0
- package/dist/packages/compiler-completion/src/compilerAsyncTaskCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerCatchCompletion.d.ts +6 -0
- package/dist/packages/compiler-completion/src/compilerCatchCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerCatchCompletion.js +77 -0
- package/dist/packages/compiler-completion/src/compilerCatchCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerCompletionSet.d.ts +6 -0
- package/dist/packages/compiler-completion/src/compilerCompletionSet.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerCompletionSet.js +110 -0
- package/dist/packages/compiler-completion/src/compilerCompletionSet.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerFinallyCompletion.d.ts +3 -0
- package/dist/packages/compiler-completion/src/compilerFinallyCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerFinallyCompletion.js +13 -0
- package/dist/packages/compiler-completion/src/compilerFinallyCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerStatementCompletion.d.ts +4 -0
- package/dist/packages/compiler-completion/src/compilerStatementCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerStatementCompletion.js +181 -0
- package/dist/packages/compiler-completion/src/compilerStatementCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerStatementValueCompletion.d.ts +5 -0
- package/dist/packages/compiler-completion/src/compilerStatementValueCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerStatementValueCompletion.js +41 -0
- package/dist/packages/compiler-completion/src/compilerStatementValueCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/compilerValueCompletion.d.ts +8 -0
- package/dist/packages/compiler-completion/src/compilerValueCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/compilerValueCompletion.js +208 -0
- package/dist/packages/compiler-completion/src/compilerValueCompletion.js.map +1 -0
- package/dist/packages/compiler-completion/src/index.d.ts +8 -0
- package/dist/packages/compiler-completion/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-completion/src/index.js +8 -0
- package/dist/packages/compiler-completion/src/index.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerEmittedSourceSyntax.d.ts +4 -0
- package/dist/packages/compiler-emission/src/compilerEmittedSourceSyntax.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerEmittedSourceSyntax.js +122 -0
- package/dist/packages/compiler-emission/src/compilerEmittedSourceSyntax.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerGeneratedFileProvenance.d.ts +3 -0
- package/dist/packages/compiler-emission/src/compilerGeneratedFileProvenance.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerGeneratedFileProvenance.js +17 -0
- package/dist/packages/compiler-emission/src/compilerGeneratedFileProvenance.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerLiteralUnion.d.ts +3 -0
- package/dist/packages/compiler-emission/src/compilerLiteralUnion.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerLiteralUnion.js +20 -0
- package/dist/packages/compiler-emission/src/compilerLiteralUnion.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerNullableFlowGuard.d.ts +4 -0
- package/dist/packages/compiler-emission/src/compilerNullableFlowGuard.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerNullableFlowGuard.js +32 -0
- package/dist/packages/compiler-emission/src/compilerNullableFlowGuard.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerSourceEmission.d.ts +16 -0
- package/dist/packages/compiler-emission/src/compilerSourceEmission.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerSourceEmission.js +176 -0
- package/dist/packages/compiler-emission/src/compilerSourceEmission.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerTargetCompilationSmoke.d.ts +4 -0
- package/dist/packages/compiler-emission/src/compilerTargetCompilationSmoke.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerTargetCompilationSmoke.js +114 -0
- package/dist/packages/compiler-emission/src/compilerTargetCompilationSmoke.js.map +1 -0
- package/dist/packages/compiler-emission/src/compilerTargetNameAllocation.d.ts +5 -0
- package/dist/packages/compiler-emission/src/compilerTargetNameAllocation.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/compilerTargetNameAllocation.js +449 -0
- package/dist/packages/compiler-emission/src/compilerTargetNameAllocation.js.map +1 -0
- package/dist/packages/compiler-emission/src/index.d.ts +8 -0
- package/dist/packages/compiler-emission/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-emission/src/index.js +8 -0
- package/dist/packages/compiler-emission/src/index.js.map +1 -0
- package/dist/packages/compiler-inventory/src/compilerInventoryFailure.d.ts +4 -0
- package/dist/packages/compiler-inventory/src/compilerInventoryFailure.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/compilerInventoryFailure.js +42 -0
- package/dist/packages/compiler-inventory/src/compilerInventoryFailure.js.map +1 -0
- package/dist/packages/compiler-inventory/src/compilerModuleResolution.d.ts +4 -0
- package/dist/packages/compiler-inventory/src/compilerModuleResolution.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/compilerModuleResolution.js +74 -0
- package/dist/packages/compiler-inventory/src/compilerModuleResolution.js.map +1 -0
- package/dist/packages/compiler-inventory/src/fileSystemWorkspaceSource.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/fileSystemWorkspaceSource.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/fileSystemWorkspaceSource.js +20 -0
- package/dist/packages/compiler-inventory/src/fileSystemWorkspaceSource.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageEligibility.d.ts +5 -0
- package/dist/packages/compiler-inventory/src/flightPackageEligibility.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageEligibility.js +174 -0
- package/dist/packages/compiler-inventory/src/flightPackageEligibility.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExclusion.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightPackageExclusion.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExclusion.js +79 -0
- package/dist/packages/compiler-inventory/src/flightPackageExclusion.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportLane.d.ts +4 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportLane.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportLane.js +30 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportLane.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportManifest.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportManifest.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportManifest.js +90 -0
- package/dist/packages/compiler-inventory/src/flightPackageExportManifest.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageHostFacts.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightPackageHostFacts.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageHostFacts.js +33 -0
- package/dist/packages/compiler-inventory/src/flightPackageHostFacts.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageImport.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightPackageImport.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageImport.js +82 -0
- package/dist/packages/compiler-inventory/src/flightPackageImport.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageManifest.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightPackageManifest.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightPackageManifest.js +116 -0
- package/dist/packages/compiler-inventory/src/flightPackageManifest.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceCompilationInput.d.ts +4 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceCompilationInput.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceCompilationInput.js +315 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceCompilationInput.js.map +1 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceInventory.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceInventory.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceInventory.js +591 -0
- package/dist/packages/compiler-inventory/src/flightWorkspaceInventory.js.map +1 -0
- package/dist/packages/compiler-inventory/src/gitCheckoutRevision.d.ts +2 -0
- package/dist/packages/compiler-inventory/src/gitCheckoutRevision.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/gitCheckoutRevision.js +20 -0
- package/dist/packages/compiler-inventory/src/gitCheckoutRevision.js.map +1 -0
- package/dist/packages/compiler-inventory/src/index.d.ts +17 -0
- package/dist/packages/compiler-inventory/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/index.js +17 -0
- package/dist/packages/compiler-inventory/src/index.js.map +1 -0
- package/dist/packages/compiler-inventory/src/memoryWorkspaceSource.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/memoryWorkspaceSource.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/memoryWorkspaceSource.js +61 -0
- package/dist/packages/compiler-inventory/src/memoryWorkspaceSource.js.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptHostEndpointInventory.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/typeScriptHostEndpointInventory.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptHostEndpointInventory.js +138 -0
- package/dist/packages/compiler-inventory/src/typeScriptHostEndpointInventory.js.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptProject.d.ts +3 -0
- package/dist/packages/compiler-inventory/src/typeScriptProject.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptProject.js +28 -0
- package/dist/packages/compiler-inventory/src/typeScriptProject.js.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptRuntimeBinding.d.ts +7 -0
- package/dist/packages/compiler-inventory/src/typeScriptRuntimeBinding.d.ts.map +1 -0
- package/dist/packages/compiler-inventory/src/typeScriptRuntimeBinding.js +67 -0
- package/dist/packages/compiler-inventory/src/typeScriptRuntimeBinding.js.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversal.d.ts +5 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversal.d.ts.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversal.js +469 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversal.js.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversalPath.d.ts +3 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversalPath.d.ts.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversalPath.js +14 -0
- package/dist/packages/compiler-ir-traversal/src/compilerIntermediateRepresentationTraversalPath.js.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/index.d.ts +3 -0
- package/dist/packages/compiler-ir-traversal/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-ir-traversal/src/index.js +3 -0
- package/dist/packages/compiler-ir-traversal/src/index.js.map +1 -0
- package/dist/packages/compiler-ir-validation/src/compilerIrModuleStructure.d.ts +3 -0
- package/dist/packages/compiler-ir-validation/src/compilerIrModuleStructure.d.ts.map +1 -0
- package/dist/packages/compiler-ir-validation/src/compilerIrModuleStructure.js +1258 -0
- package/dist/packages/compiler-ir-validation/src/compilerIrModuleStructure.js.map +1 -0
- package/dist/packages/compiler-ir-validation/src/index.d.ts +2 -0
- package/dist/packages/compiler-ir-validation/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-ir-validation/src/index.js +2 -0
- package/dist/packages/compiler-ir-validation/src/index.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternLowering.js +717 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternPresence.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternPresence.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternPresence.js +162 -0
- package/dist/packages/compiler-lowering/src/compilerArrayBindingPatternPresence.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerAwaitConditionHoistingLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerAwaitConditionHoistingLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerAwaitConditionHoistingLowering.js +721 -0
- package/dist/packages/compiler-lowering/src/compilerAwaitConditionHoistingLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerBindingPatternLowering.d.ts +4 -0
- package/dist/packages/compiler-lowering/src/compilerBindingPatternLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerBindingPatternLowering.js +43 -0
- package/dist/packages/compiler-lowering/src/compilerBindingPatternLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerCStyleForLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerCStyleForLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerCStyleForLowering.js +591 -0
- package/dist/packages/compiler-lowering/src/compilerCStyleForLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerCatchAwaitHoistingLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerCatchAwaitHoistingLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerCatchAwaitHoistingLowering.js +244 -0
- package/dist/packages/compiler-lowering/src/compilerCatchAwaitHoistingLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerClassInitialization.d.ts +4 -0
- package/dist/packages/compiler-lowering/src/compilerClassInitialization.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerClassInitialization.js +102 -0
- package/dist/packages/compiler-lowering/src/compilerClassInitialization.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerExtraArgumentErasureLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerExtraArgumentErasureLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerExtraArgumentErasureLowering.js +156 -0
- package/dist/packages/compiler-lowering/src/compilerExtraArgumentErasureLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerFinallyAwaitHoistingLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerFinallyAwaitHoistingLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerFinallyAwaitHoistingLowering.js +255 -0
- package/dist/packages/compiler-lowering/src/compilerFinallyAwaitHoistingLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerInterfaceInheritanceLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerInterfaceInheritanceLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerInterfaceInheritanceLowering.js +1062 -0
- package/dist/packages/compiler-lowering/src/compilerInterfaceInheritanceLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerLoweringPass.d.ts +5 -0
- package/dist/packages/compiler-lowering/src/compilerLoweringPass.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerLoweringPass.js +133 -0
- package/dist/packages/compiler-lowering/src/compilerLoweringPass.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerObjectBindingPatternLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerObjectBindingPatternLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerObjectBindingPatternLowering.js +589 -0
- package/dist/packages/compiler-lowering/src/compilerObjectBindingPatternLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchClauseCompletion.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchClauseCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchClauseCompletion.js +71 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchClauseCompletion.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchFallthroughLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchFallthroughLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchFallthroughLowering.js +810 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchFallthroughLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchSuspensionLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchSuspensionLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchSuspensionLowering.js +226 -0
- package/dist/packages/compiler-lowering/src/compilerSwitchSuspensionLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingInitialization.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingInitialization.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingInitialization.js +724 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingInitialization.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingLowering.d.ts +3 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingLowering.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingLowering.js +797 -0
- package/dist/packages/compiler-lowering/src/compilerVariableHoistingLowering.js.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableInitializationCompletion.d.ts +9 -0
- package/dist/packages/compiler-lowering/src/compilerVariableInitializationCompletion.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/compilerVariableInitializationCompletion.js +42 -0
- package/dist/packages/compiler-lowering/src/compilerVariableInitializationCompletion.js.map +1 -0
- package/dist/packages/compiler-lowering/src/index.d.ts +17 -0
- package/dist/packages/compiler-lowering/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-lowering/src/index.js +17 -0
- package/dist/packages/compiler-lowering/src/index.js.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleEvaluation.d.ts +4 -0
- package/dist/packages/compiler-module/src/compilerModuleEvaluation.d.ts.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleEvaluation.js +506 -0
- package/dist/packages/compiler-module/src/compilerModuleEvaluation.js.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeIdentity.d.ts +4 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeIdentity.js +182 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeIdentity.js.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeLowering.d.ts +4 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeLowering.d.ts.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeLowering.js +466 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeLowering.js.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeRequirement.d.ts +3 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeRequirement.d.ts.map +1 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeRequirement.js +28 -0
- package/dist/packages/compiler-module/src/compilerModuleFacadeRequirement.js.map +1 -0
- package/dist/packages/compiler-module/src/index.d.ts +5 -0
- package/dist/packages/compiler-module/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-module/src/index.js +5 -0
- package/dist/packages/compiler-module/src/index.js.map +1 -0
- package/dist/packages/compiler-orchestration/src/compilerOrchestration.d.ts +8 -0
- package/dist/packages/compiler-orchestration/src/compilerOrchestration.d.ts.map +1 -0
- package/dist/packages/compiler-orchestration/src/compilerOrchestration.js +161 -0
- package/dist/packages/compiler-orchestration/src/compilerOrchestration.js.map +1 -0
- package/dist/packages/compiler-orchestration/src/compilerPackageCompilation.d.ts +4 -0
- package/dist/packages/compiler-orchestration/src/compilerPackageCompilation.d.ts.map +1 -0
- package/dist/packages/compiler-orchestration/src/compilerPackageCompilation.js +745 -0
- package/dist/packages/compiler-orchestration/src/compilerPackageCompilation.js.map +1 -0
- package/dist/packages/compiler-orchestration/src/flightWorkspaceCompilation.d.ts +3 -0
- package/dist/packages/compiler-orchestration/src/flightWorkspaceCompilation.d.ts.map +1 -0
- package/dist/packages/compiler-orchestration/src/flightWorkspaceCompilation.js +14 -0
- package/dist/packages/compiler-orchestration/src/flightWorkspaceCompilation.js.map +1 -0
- package/dist/packages/compiler-orchestration/src/index.d.ts +4 -0
- package/dist/packages/compiler-orchestration/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-orchestration/src/index.js +4 -0
- package/dist/packages/compiler-orchestration/src/index.js.map +1 -0
- package/dist/packages/compiler-patch/src/compilerSemanticPatch.d.ts +6 -0
- package/dist/packages/compiler-patch/src/compilerSemanticPatch.d.ts.map +1 -0
- package/dist/packages/compiler-patch/src/compilerSemanticPatch.js +316 -0
- package/dist/packages/compiler-patch/src/compilerSemanticPatch.js.map +1 -0
- package/dist/packages/compiler-patch/src/index.d.ts +2 -0
- package/dist/packages/compiler-patch/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-patch/src/index.js +2 -0
- package/dist/packages/compiler-patch/src/index.js.map +1 -0
- package/dist/packages/compiler-provenance/src/index.d.ts +2 -0
- package/dist/packages/compiler-provenance/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-provenance/src/index.js +2 -0
- package/dist/packages/compiler-provenance/src/index.js.map +1 -0
- package/dist/packages/compiler-provenance/src/sourceFingerprint.d.ts +7 -0
- package/dist/packages/compiler-provenance/src/sourceFingerprint.d.ts.map +1 -0
- package/dist/packages/compiler-provenance/src/sourceFingerprint.js +58 -0
- package/dist/packages/compiler-provenance/src/sourceFingerprint.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorAbiCompleteness.d.ts +4 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorAbiCompleteness.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorAbiCompleteness.js +110 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorAbiCompleteness.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorReachability.d.ts +3 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorReachability.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorReachability.js +42 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalConstructorReachability.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolCompleteness.d.ts +4 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolCompleteness.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolCompleteness.js +64 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolCompleteness.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolReachability.d.ts +3 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolReachability.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolReachability.js +89 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeExternalSymbolReachability.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeTaskCapability.d.ts +6 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeTaskCapability.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeTaskCapability.js +247 -0
- package/dist/packages/compiler-runtime-contract/src/compilerRuntimeTaskCapability.js.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/index.d.ts +6 -0
- package/dist/packages/compiler-runtime-contract/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-runtime-contract/src/index.js +6 -0
- package/dist/packages/compiler-runtime-contract/src/index.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerIrStaticFacts.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/compilerIrStaticFacts.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerIrStaticFacts.js +396 -0
- package/dist/packages/compiler-semantic/src/compilerIrStaticFacts.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerIrTypeMemberEvidence.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/compilerIrTypeMemberEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerIrTypeMemberEvidence.js +63 -0
- package/dist/packages/compiler-semantic/src/compilerIrTypeMemberEvidence.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerOperatorDomainEvidence.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/compilerOperatorDomainEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerOperatorDomainEvidence.js +76 -0
- package/dist/packages/compiler-semantic/src/compilerOperatorDomainEvidence.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerStaticNumericArithmetic.d.ts +7 -0
- package/dist/packages/compiler-semantic/src/compilerStaticNumericArithmetic.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerStaticNumericArithmetic.js +107 -0
- package/dist/packages/compiler-semantic/src/compilerStaticNumericArithmetic.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptForInKeyEvidence.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptForInKeyEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptForInKeyEvidence.js +159 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptForInKeyEvidence.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptInvocationSemantics.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptInvocationSemantics.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptInvocationSemantics.js +31 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptInvocationSemantics.js.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptSyntacticTypeEvidence.d.ts +8 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptSyntacticTypeEvidence.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptSyntacticTypeEvidence.js +83 -0
- package/dist/packages/compiler-semantic/src/compilerTypeScriptSyntacticTypeEvidence.js.map +1 -0
- package/dist/packages/compiler-semantic/src/index.d.ts +4 -0
- package/dist/packages/compiler-semantic/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/index.js +4 -0
- package/dist/packages/compiler-semantic/src/index.js.map +1 -0
- package/dist/packages/compiler-semantic/src/typeScriptSemanticLowering.d.ts +6 -0
- package/dist/packages/compiler-semantic/src/typeScriptSemanticLowering.d.ts.map +1 -0
- package/dist/packages/compiler-semantic/src/typeScriptSemanticLowering.js +8158 -0
- package/dist/packages/compiler-semantic/src/typeScriptSemanticLowering.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCompatibility.d.ts +5 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCompatibility.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCompatibility.js +500 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCompatibility.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCopySemantics.d.ts +3 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCopySemantics.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCopySemantics.js +11 -0
- package/dist/packages/compiler-structural/src/compilerStructuralObjectCopySemantics.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeAssignability.d.ts +4 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeAssignability.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeAssignability.js +261 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeAssignability.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeIdentity.d.ts +4 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeIdentity.js +168 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeIdentity.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeInventory.d.ts +3 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeInventory.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeInventory.js +50 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeShapeInventory.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeSubstitution.d.ts +5 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeSubstitution.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeSubstitution.js +224 -0
- package/dist/packages/compiler-structural/src/compilerStructuralTypeSubstitution.js.map +1 -0
- package/dist/packages/compiler-structural/src/compilerTypeValueIdentityAnalysis.d.ts +4 -0
- package/dist/packages/compiler-structural/src/compilerTypeValueIdentityAnalysis.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/compilerTypeValueIdentityAnalysis.js +592 -0
- package/dist/packages/compiler-structural/src/compilerTypeValueIdentityAnalysis.js.map +1 -0
- package/dist/packages/compiler-structural/src/index.d.ts +8 -0
- package/dist/packages/compiler-structural/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-structural/src/index.js +8 -0
- package/dist/packages/compiler-structural/src/index.js.map +1 -0
- package/dist/packages/compiler-task/src/compilerAsyncStateMachine.d.ts +3 -0
- package/dist/packages/compiler-task/src/compilerAsyncStateMachine.d.ts.map +1 -0
- package/dist/packages/compiler-task/src/compilerAsyncStateMachine.js +785 -0
- package/dist/packages/compiler-task/src/compilerAsyncStateMachine.js.map +1 -0
- package/dist/packages/compiler-task/src/compilerAsyncTaskInventory.d.ts +3 -0
- package/dist/packages/compiler-task/src/compilerAsyncTaskInventory.d.ts.map +1 -0
- package/dist/packages/compiler-task/src/compilerAsyncTaskInventory.js +182 -0
- package/dist/packages/compiler-task/src/compilerAsyncTaskInventory.js.map +1 -0
- package/dist/packages/compiler-task/src/compilerTaskOperationSemantics.d.ts +4 -0
- package/dist/packages/compiler-task/src/compilerTaskOperationSemantics.d.ts.map +1 -0
- package/dist/packages/compiler-task/src/compilerTaskOperationSemantics.js +101 -0
- package/dist/packages/compiler-task/src/compilerTaskOperationSemantics.js.map +1 -0
- package/dist/packages/compiler-task/src/index.d.ts +4 -0
- package/dist/packages/compiler-task/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-task/src/index.js +4 -0
- package/dist/packages/compiler-task/src/index.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerAccessSemanticIntermediateRepresentation.d.ts +79 -0
- package/dist/packages/compiler-types/src/compilerAccessSemanticIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerAccessSemanticIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerAccessSemanticIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerAmbientMemberBindingContract.d.ts +87 -0
- package/dist/packages/compiler-types/src/compilerAmbientMemberBindingContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerAmbientMemberBindingContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerAmbientMemberBindingContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncStateMachineContract.d.ts +126 -0
- package/dist/packages/compiler-types/src/compilerAsyncStateMachineContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncStateMachineContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerAsyncStateMachineContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskCompletionContract.d.ts +32 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskCompletionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskCompletionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskCompletionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskInventoryContract.d.ts +63 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskInventoryContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskInventoryContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerAsyncTaskInventoryContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerBackendContract.d.ts +183 -0
- package/dist/packages/compiler-types/src/compilerBackendContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerBackendContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerBackendContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerBindingIntermediateRepresentation.d.ts +46 -0
- package/dist/packages/compiler-types/src/compilerBindingIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerBindingIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerBindingIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerBindingPatternIntermediateRepresentation.d.ts +43 -0
- package/dist/packages/compiler-types/src/compilerBindingPatternIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerBindingPatternIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerBindingPatternIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerCatchCompletionContract.d.ts +23 -0
- package/dist/packages/compiler-types/src/compilerCatchCompletionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerCatchCompletionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerCatchCompletionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerClassInitializationContract.d.ts +30 -0
- package/dist/packages/compiler-types/src/compilerClassInitializationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerClassInitializationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerClassInitializationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerClosureEvidenceContract.d.ts +60 -0
- package/dist/packages/compiler-types/src/compilerClosureEvidenceContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerClosureEvidenceContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerClosureEvidenceContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerCommandLineContract.d.ts +79 -0
- package/dist/packages/compiler-types/src/compilerCommandLineContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerCommandLineContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerCommandLineContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerCompletionContract.d.ts +25 -0
- package/dist/packages/compiler-types/src/compilerCompletionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerCompletionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerCompletionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerCppClosureCaptureContract.d.ts +21 -0
- package/dist/packages/compiler-types/src/compilerCppClosureCaptureContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerCppClosureCaptureContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerCppClosureCaptureContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerCppReferenceRepresentationContract.d.ts +74 -0
- package/dist/packages/compiler-types/src/compilerCppReferenceRepresentationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerCppReferenceRepresentationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerCppReferenceRepresentationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerDeclarationIntermediateRepresentation.d.ts +113 -0
- package/dist/packages/compiler-types/src/compilerDeclarationIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerDeclarationIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerDeclarationIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerDependentCallablePackContract.d.ts +11 -0
- package/dist/packages/compiler-types/src/compilerDependentCallablePackContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerDependentCallablePackContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerDependentCallablePackContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerDiagnosticContract.d.ts +11 -0
- package/dist/packages/compiler-types/src/compilerDiagnosticContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerDiagnosticContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerDiagnosticContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerEmittedSourceSyntaxContract.d.ts +28 -0
- package/dist/packages/compiler-types/src/compilerEmittedSourceSyntaxContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerEmittedSourceSyntaxContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerEmittedSourceSyntaxContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerExecutableIntermediateRepresentation.d.ts +343 -0
- package/dist/packages/compiler-types/src/compilerExecutableIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerExecutableIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerExecutableIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerFlightWorkspaceContract.d.ts +26 -0
- package/dist/packages/compiler-types/src/compilerFlightWorkspaceContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerFlightWorkspaceContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerFlightWorkspaceContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskEmissionContract.d.ts +12 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskEmissionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskEmissionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskEmissionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskLoweringContract.d.ts +119 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskLoweringContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskLoweringContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerHaxeTaskLoweringContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerHostEndpointContract.d.ts +27 -0
- package/dist/packages/compiler-types/src/compilerHostEndpointContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerHostEndpointContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerHostEndpointContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerInvariantContract.d.ts +7 -0
- package/dist/packages/compiler-types/src/compilerInvariantContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerInvariantContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerInvariantContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerInventoryContract.d.ts +186 -0
- package/dist/packages/compiler-types/src/compilerInventoryContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerInventoryContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerInventoryContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerIrValidationContract.d.ts +13 -0
- package/dist/packages/compiler-types/src/compilerIrValidationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerIrValidationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerIrValidationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerLoweringContract.d.ts +32 -0
- package/dist/packages/compiler-types/src/compilerLoweringContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerLoweringContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerLoweringContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleEvaluationContract.d.ts +84 -0
- package/dist/packages/compiler-types/src/compilerModuleEvaluationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleEvaluationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerModuleEvaluationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleFacadeContract.d.ts +78 -0
- package/dist/packages/compiler-types/src/compilerModuleFacadeContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleFacadeContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerModuleFacadeContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleIntermediateRepresentation.d.ts +53 -0
- package/dist/packages/compiler-types/src/compilerModuleIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerModuleIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleResolutionContract.d.ts +20 -0
- package/dist/packages/compiler-types/src/compilerModuleResolutionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerModuleResolutionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerModuleResolutionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerOperatorIntermediateRepresentation.d.ts +5 -0
- package/dist/packages/compiler-types/src/compilerOperatorIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerOperatorIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerOperatorIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerOperatorSemanticIntermediateRepresentation.d.ts +34 -0
- package/dist/packages/compiler-types/src/compilerOperatorSemanticIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerOperatorSemanticIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerOperatorSemanticIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerOrchestrationContract.d.ts +43 -0
- package/dist/packages/compiler-types/src/compilerOrchestrationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerOrchestrationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerOrchestrationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerPackageCheckContract.d.ts +96 -0
- package/dist/packages/compiler-types/src/compilerPackageCheckContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerPackageCheckContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerPackageCheckContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerPackageCompilationContract.d.ts +108 -0
- package/dist/packages/compiler-types/src/compilerPackageCompilationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerPackageCompilationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerPackageCompilationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerRefusalClassificationContract.d.ts +3 -0
- package/dist/packages/compiler-types/src/compilerRefusalClassificationContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerRefusalClassificationContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerRefusalClassificationContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerRuntimeContract.d.ts +122 -0
- package/dist/packages/compiler-types/src/compilerRuntimeContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerRuntimeContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerRuntimeContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerRuntimeTaskCapabilityContract.d.ts +96 -0
- package/dist/packages/compiler-types/src/compilerRuntimeTaskCapabilityContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerRuntimeTaskCapabilityContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerRuntimeTaskCapabilityContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerRustOwnershipContract.d.ts +25 -0
- package/dist/packages/compiler-types/src/compilerRustOwnershipContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerRustOwnershipContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerRustOwnershipContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerSemanticPatchContract.d.ts +80 -0
- package/dist/packages/compiler-types/src/compilerSemanticPatchContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerSemanticPatchContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerSemanticPatchContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerSourceFingerprint.d.ts +2 -0
- package/dist/packages/compiler-types/src/compilerSourceFingerprint.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerSourceFingerprint.js +2 -0
- package/dist/packages/compiler-types/src/compilerSourceFingerprint.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerSourceIdentity.d.ts +21 -0
- package/dist/packages/compiler-types/src/compilerSourceIdentity.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerSourceIdentity.js +2 -0
- package/dist/packages/compiler-types/src/compilerSourceIdentity.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStatementCompletionContract.d.ts +7 -0
- package/dist/packages/compiler-types/src/compilerStatementCompletionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStatementCompletionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStatementCompletionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStaticFactContract.d.ts +71 -0
- package/dist/packages/compiler-types/src/compilerStaticFactContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStaticFactContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStaticFactContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralObjectCompatibilityContract.d.ts +18 -0
- package/dist/packages/compiler-types/src/compilerStructuralObjectCompatibilityContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralObjectCompatibilityContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStructuralObjectCompatibilityContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeAssignabilityContract.d.ts +20 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeAssignabilityContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeAssignabilityContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeAssignabilityContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeShapeContract.d.ts +22 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeShapeContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeShapeContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeShapeContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeSubstitutionContract.d.ts +17 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeSubstitutionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeSubstitutionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerStructuralTypeSubstitutionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTargetCompilationSmokeContract.d.ts +26 -0
- package/dist/packages/compiler-types/src/compilerTargetCompilationSmokeContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTargetCompilationSmokeContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTargetCompilationSmokeContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTargetNamingContract.d.ts +27 -0
- package/dist/packages/compiler-types/src/compilerTargetNamingContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTargetNamingContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTargetNamingContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTaskOperationSemanticsContract.d.ts +65 -0
- package/dist/packages/compiler-types/src/compilerTaskOperationSemanticsContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTaskOperationSemanticsContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTaskOperationSemanticsContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTraversalObserverContract.d.ts +29 -0
- package/dist/packages/compiler-types/src/compilerTraversalObserverContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTraversalObserverContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTraversalObserverContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeIntermediateRepresentation.d.ts +99 -0
- package/dist/packages/compiler-types/src/compilerTypeIntermediateRepresentation.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeIntermediateRepresentation.js +2 -0
- package/dist/packages/compiler-types/src/compilerTypeIntermediateRepresentation.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeScriptContract.d.ts +39 -0
- package/dist/packages/compiler-types/src/compilerTypeScriptContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeScriptContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTypeScriptContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeValueIdentityContract.d.ts +14 -0
- package/dist/packages/compiler-types/src/compilerTypeValueIdentityContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerTypeValueIdentityContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerTypeValueIdentityContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerValueCompletionContract.d.ts +46 -0
- package/dist/packages/compiler-types/src/compilerValueCompletionContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerValueCompletionContract.js +2 -0
- package/dist/packages/compiler-types/src/compilerValueCompletionContract.js.map +1 -0
- package/dist/packages/compiler-types/src/compilerWorkspaceSourceContract.d.ts +11 -0
- package/dist/packages/compiler-types/src/compilerWorkspaceSourceContract.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/compilerWorkspaceSourceContract.js +12 -0
- package/dist/packages/compiler-types/src/compilerWorkspaceSourceContract.js.map +1 -0
- package/dist/packages/compiler-types/src/index.d.ts +60 -0
- package/dist/packages/compiler-types/src/index.d.ts.map +1 -0
- package/dist/packages/compiler-types/src/index.js +2 -0
- package/dist/packages/compiler-types/src/index.js.map +1 -0
- package/dist/packages/tool-compiler/src/index.d.ts +24 -0
- package/dist/packages/tool-compiler/src/index.d.ts.map +1 -0
- package/dist/packages/tool-compiler/src/index.js +23 -0
- package/dist/packages/tool-compiler/src/index.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,4555 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { analyzeIrModuleClosureEvidence } from '../../compiler-closure/src/index.js';
|
|
3
|
+
import { collectIrModuleNullableBindingIds, createBackendEmissionFailure, createCompilerGeneratedFileHeader, createIrModuleTargetNameAllocation, getIrUnionTypeStringLiteralValues, hasIrTypeAbsentMember, indentSourceLines, normalizeSourceTextGrouping, isCompilerTargetNameAllocationFailure, } from '../../compiler-emission/src/index.js';
|
|
4
|
+
import { analyzeIrModuleTraversal, analyzeIrStatementSubtreeTraversal, getIrModuleTraversalPathValue, } from '../../compiler-ir-traversal/src/index.js';
|
|
5
|
+
import { createIrClassInitializationPlan, createCompilerLoweringPassAwaitConditionHoisting, createCompilerLoweringPassBindingPattern, createCompilerLoweringPassCStyleFor, createCompilerLoweringPassExtraArgumentErasure, createCompilerLoweringPassInterfaceInheritance, createCompilerLoweringPassSwitchFallthrough, createCompilerLoweringPassSwitchSuspension, createCompilerLoweringPassVariableHoisting, lowerIrModuleWithCompilerPasses, } from '../../compiler-lowering/src/index.js';
|
|
6
|
+
import { analyzeCompilerRuntimeExternalConstructorAbiCompleteness, analyzeCompilerRuntimeExternalSymbolCompleteness, collectIrModulesRuntimeExternalConstructorInvocations, collectIrModulesRuntimeExternalSymbolIdentities, } from '../../compiler-runtime-contract/src/index.js';
|
|
7
|
+
import { analyzeIrModuleStructuralObjectCompatibilityAcrossModules, analyzeIrTypeStructuralAssignability, createIrObjectTypeShapeIdentity, createIrTypeParameterSubstitutionPlan, isCompilerStructuralTypeSubstitutionFailure, resolveIrTypeStructuralSubstitution, } from '../../compiler-structural/src/index.js';
|
|
8
|
+
import { analyzeIrModuleAsyncStateMachines } from '../../compiler-task/src/index.js';
|
|
9
|
+
import { getCompilerRustAmbientMemberBinding } from './rustAmbientMemberBinding.js';
|
|
10
|
+
import { convertPackageNameToRustCrateName, convertSourcePathToRustModuleName, isRustCompilerKeyword, } from './rustCompilerIdentity.js';
|
|
11
|
+
import { analyzeIrModuleOwnershipEvidenceRust, collectIrModuleMovedBindingIdsRust, collectIrModuleReferentMutatedParameterIdsRust, } from './rustOwnershipEvidence.js';
|
|
12
|
+
import { createCompilerRuntimeExternalConstructorAbiPlanRust } from './rustRuntimeExternalConstructorAbi.js';
|
|
13
|
+
import { createCompilerRuntimeExternalSymbolBindingPlanRust, getCompilerRuntimeExternalMemberTargetRust, getCompilerRuntimeExternalSymbolTargetRust, isCompilerRuntimeExternalSymbolProvidedRust, } from './rustRuntimeExternalSymbolBinding.js';
|
|
14
|
+
export function createRustCompilerBackend() {
|
|
15
|
+
return {
|
|
16
|
+
emitModule(module, { moduleResolution, modules, options }) {
|
|
17
|
+
return [emitIrModuleRustWithContext(module, modules, moduleResolution, options)];
|
|
18
|
+
},
|
|
19
|
+
name: 'rust',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function emitIrModuleRust(sourceModule, options = {}) {
|
|
23
|
+
return emitIrModuleRustWithContext(sourceModule, [sourceModule], undefined, options);
|
|
24
|
+
}
|
|
25
|
+
function createCompilerLoweringPassInterfaceInheritanceRust(modules, moduleResolution) {
|
|
26
|
+
return createCompilerLoweringPassInterfaceInheritance(modules, moduleResolution, {
|
|
27
|
+
// TypeScript has already materialized every selected ambient member on the interface. The
|
|
28
|
+
// shared pass verifies that evidence before it erases the otherwise nonlocal DOM heritage.
|
|
29
|
+
eraseAmbientUtilityHeritage: (reference) => reference.reference.kind === 'ambient' && reference.reference.name === 'Pick',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function emitIrModuleRustWithContext(sourceModule, sourceModules, moduleResolution, options) {
|
|
33
|
+
const module = lowerIrModuleWithCompilerPasses(sourceModule, [
|
|
34
|
+
createCompilerLoweringPassExtraArgumentErasure(),
|
|
35
|
+
createCompilerLoweringPassAwaitConditionHoisting(),
|
|
36
|
+
createCompilerLoweringPassBindingPattern(),
|
|
37
|
+
createCompilerLoweringPassVariableHoisting(),
|
|
38
|
+
createCompilerLoweringPassCStyleFor(),
|
|
39
|
+
createCompilerLoweringPassInterfaceInheritanceRust(sourceModules, moduleResolution),
|
|
40
|
+
createCompilerLoweringPassSwitchFallthrough(),
|
|
41
|
+
createCompilerLoweringPassSwitchSuspension(),
|
|
42
|
+
]);
|
|
43
|
+
assertStructuralObjectCompatibilityRust(module, replaceIrModuleBackendContext(sourceModules, module), moduleResolution);
|
|
44
|
+
assertRuntimeExternalSymbolBindingsRust(module, options);
|
|
45
|
+
assertRuntimeExternalConstructorAbiRust(module);
|
|
46
|
+
const asyncAnalysis = analyzeIrModuleAsyncStateMachines(module);
|
|
47
|
+
const asyncTryStatements = collectAsyncTryStatementsRust(module, asyncAnalysis);
|
|
48
|
+
const constantIdentities = new Set(module.declarations.flatMap((declaration) => declaration.kind === 'variable' && !declaration.mutable && !('pattern' in declaration)
|
|
49
|
+
? [declaration.binding.id]
|
|
50
|
+
: []));
|
|
51
|
+
let targetNames;
|
|
52
|
+
try {
|
|
53
|
+
targetNames = new Map(createIrModuleTargetNameAllocation(module, (binding) => ({
|
|
54
|
+
namespace: 'identifier',
|
|
55
|
+
preferredName: getPreferredBindingNameRust(binding, constantIdentities),
|
|
56
|
+
})).map((allocation) => [allocation.identity, allocation.name]));
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (isCompilerTargetNameAllocationFailure(error)) {
|
|
60
|
+
throw createBackendEmissionFailure('rust', module, `public declarations share fixed Rust target name ${error.targetName}`);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
const closureEvidence = analyzeIrModuleClosureEvidence(module);
|
|
65
|
+
const bindingTypes = collectIrModuleBindingTypesRust(module);
|
|
66
|
+
const allCellWrappedIds = closureEvidence.closures
|
|
67
|
+
.filter((closure) => closure.origin.kind === 'functionExpression' &&
|
|
68
|
+
!closure.valueUses.every((use) => use.kind === 'directInvocation'))
|
|
69
|
+
.flatMap((closure) => closure.captures.filter((capture) => capture.mutation !== 'none').map((capture) => capture.binding.id));
|
|
70
|
+
const cellWrappedBindingIds = new Set(allCellWrappedIds.filter((id) => {
|
|
71
|
+
const type = bindingTypes.get(id);
|
|
72
|
+
return !type || isIrTypeCopyRust(type);
|
|
73
|
+
}));
|
|
74
|
+
const refCellWrappedBindingIds = new Set(allCellWrappedIds.filter((id) => {
|
|
75
|
+
const type = bindingTypes.get(id);
|
|
76
|
+
return type !== undefined && !isIrTypeCopyRust(type);
|
|
77
|
+
}));
|
|
78
|
+
const accessorClassNames = new Map();
|
|
79
|
+
const classBindingNames = new Map();
|
|
80
|
+
const borrowedParameterPositions = new Map();
|
|
81
|
+
const primitiveUnionEnums = new Map();
|
|
82
|
+
const primitiveUnionBindingIds = new Map();
|
|
83
|
+
const taggedUnionBindingNames = new Map();
|
|
84
|
+
const numericEnumNamespaceNames = new Map(module.declarations.flatMap((declaration) => declaration.kind === 'enum' && getIrEnumNamespaceFunctionsRust(declaration, module).length > 0
|
|
85
|
+
? [
|
|
86
|
+
[
|
|
87
|
+
declaration.binding.id,
|
|
88
|
+
targetNames.get(declaration.binding.id) ?? safeRustTypeName(declaration.binding.name),
|
|
89
|
+
],
|
|
90
|
+
]
|
|
91
|
+
: []));
|
|
92
|
+
const context = {
|
|
93
|
+
abstractFieldNames: new Set(),
|
|
94
|
+
activeTypeParameters: [],
|
|
95
|
+
assertedUnknownBindingTypes: collectAssertedUnknownBindingTypesRust(module, bindingTypes),
|
|
96
|
+
accessorClassNames,
|
|
97
|
+
anonymousObjectRecords: new Map(),
|
|
98
|
+
anonymousUnionEnums: new Map(),
|
|
99
|
+
apiReferencedBindingIds: collectIrModuleApiReferencedBindingIdsRust(module),
|
|
100
|
+
arrayElementBindingIds: collectIrModuleArrayElementBindingIdsRust(module),
|
|
101
|
+
asyncTryStatements,
|
|
102
|
+
cellWrappedBindingIds,
|
|
103
|
+
refCellWrappedBindingIds,
|
|
104
|
+
classBindingNames,
|
|
105
|
+
borrowedParameterPositions,
|
|
106
|
+
callableObjectRecords: new Map(),
|
|
107
|
+
deferredBindingIds: new Set(analyzeIrModuleOwnershipEvidenceRust(module).bindings.flatMap((evidence) => evidence.uses.filter((use) => use.kind === 'rebind').length === 1 ? [evidence.binding.id] : [])),
|
|
108
|
+
primitiveUnionEnums,
|
|
109
|
+
primitiveUnionBindingIds,
|
|
110
|
+
runtimeTypeNames: new Set(),
|
|
111
|
+
reboundBindingIds: new Set(analyzeIrModuleOwnershipEvidenceRust(module).bindings.flatMap((evidence) => evidence.mutation !== 'none' ? [evidence.binding.id] : [])),
|
|
112
|
+
generatedNames: new Set(targetNames.values()),
|
|
113
|
+
movedBindingIds: collectIrModuleMovedBindingIdsRust(module),
|
|
114
|
+
referentMutatedBindingIds: new Set(analyzeIrModuleOwnershipEvidenceRust(module).bindings.flatMap((evidence) => evidence.mutation === 'referentMutated' || evidence.mutation === 'bindingAndReferent'
|
|
115
|
+
? [evidence.binding.id]
|
|
116
|
+
: [])),
|
|
117
|
+
referentMutatedParameterIds: collectIrModuleReferentMutatedParameterIdsRust(module),
|
|
118
|
+
taggedUnionBindingNames,
|
|
119
|
+
bindingTypes,
|
|
120
|
+
module,
|
|
121
|
+
moduleResolution,
|
|
122
|
+
sourceModules: replaceIrModuleBackendContext(sourceModules, module),
|
|
123
|
+
needsCellImport: new Set(),
|
|
124
|
+
needsRcImport: new Set(),
|
|
125
|
+
needsRefCellImport: new Set(),
|
|
126
|
+
nullableBindingIds: collectIrModuleNullableBindingIds(module),
|
|
127
|
+
numericEnumNamespaceNames,
|
|
128
|
+
objectRestRecords: new Map(),
|
|
129
|
+
options,
|
|
130
|
+
returnsAbsent: false,
|
|
131
|
+
targetNames,
|
|
132
|
+
};
|
|
133
|
+
// Which bindings hold a union this module lowered to an enum. The type is on the binding, not on
|
|
134
|
+
// the member access, so the access site can only tell that its object is an enum by asking here.
|
|
135
|
+
for (const evidence of analyzeIrModuleOwnershipEvidenceRust(module).bindings) {
|
|
136
|
+
if (evidence.type.kind !== 'named' || evidence.type.reference.kind !== 'binding')
|
|
137
|
+
continue;
|
|
138
|
+
const reference = evidence.type.reference;
|
|
139
|
+
const alias = module.declarations.find((candidate) => candidate.kind === 'typeAlias' && candidate.binding.name === reference.binding.name);
|
|
140
|
+
if (alias?.kind === 'typeAlias' &&
|
|
141
|
+
alias.type.kind === 'union' &&
|
|
142
|
+
getIrUnionTypeMemberRecordsRust(alias.type, context)) {
|
|
143
|
+
taggedUnionBindingNames.set(evidence.binding.id, getBindingTargetNameRust(alias.binding, context));
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// Which bindings hold a class with accessors. Rust has no properties, so a source-level field
|
|
147
|
+
// read of one is a call, and the access site can only tell by asking what the binding holds.
|
|
148
|
+
const classDeclaration = module.declarations.find((candidate) => candidate.kind === 'class' && candidate.binding.name === reference.binding.name);
|
|
149
|
+
if (classDeclaration?.kind !== 'class')
|
|
150
|
+
continue;
|
|
151
|
+
classBindingNames.set(evidence.binding.id, classDeclaration.binding.name);
|
|
152
|
+
if (classDeclaration.methods.some((method) => method.accessor)) {
|
|
153
|
+
accessorClassNames.set(evidence.binding.id, classDeclaration.binding.name);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Which positions each module-local function borrows. Rust does not take a reference for an
|
|
157
|
+
// argument the way it does for a method receiver, so the call site has to lend explicitly, and only
|
|
158
|
+
// the callee's own declaration knows which positions those are.
|
|
159
|
+
for (const declaration of module.declarations) {
|
|
160
|
+
if (declaration.kind !== 'function')
|
|
161
|
+
continue;
|
|
162
|
+
const borrowed = new Set(declaration.parameters.flatMap((parameter, index) => context.referentMutatedParameterIds.has(parameter.binding.id) ? [index] : []));
|
|
163
|
+
if (borrowed.size > 0)
|
|
164
|
+
borrowedParameterPositions.set(declaration.binding.id, borrowed);
|
|
165
|
+
}
|
|
166
|
+
collectPrimitiveUnionBindingsRust(module, context);
|
|
167
|
+
const lines = [createCompilerGeneratedFileHeader(module, '//', options.upstreamCommit), '#![forbid(unsafe_code)]'];
|
|
168
|
+
const imports = [...emitImports(module.imports, context), ...emitReexportsRust(module.exports, context)];
|
|
169
|
+
const declarations = module.declarations
|
|
170
|
+
.filter((declaration) => declaration.kind !== 'function' || !declaration.namespaceMember)
|
|
171
|
+
.map((declaration) => emitDeclaration(declaration, context));
|
|
172
|
+
// The runtime contract's types are named bare in emitted source, so the module has to bring them
|
|
173
|
+
// into scope. Which ones it needs is only known once everything is emitted, which is why the use
|
|
174
|
+
// line is assembled here rather than beside the source's own imports.
|
|
175
|
+
const runtimeImports = context.runtimeTypeNames.size > 0
|
|
176
|
+
? [`use ${options.runtimeCrate ?? 'flight_runtime'}::${emitUseTreeRust([...context.runtimeTypeNames].sort())};`]
|
|
177
|
+
: [];
|
|
178
|
+
const stdImports = [];
|
|
179
|
+
if (context.needsCellImport.size > 0)
|
|
180
|
+
stdImports.push('use std::cell::Cell;');
|
|
181
|
+
if (context.needsRefCellImport.size > 0)
|
|
182
|
+
stdImports.push('use std::cell::RefCell;');
|
|
183
|
+
if (context.needsRcImport.size > 0)
|
|
184
|
+
stdImports.push('use std::rc::Rc;');
|
|
185
|
+
if (runtimeImports.length > 0 || imports.length > 0 || stdImports.length > 0)
|
|
186
|
+
lines.push('', ...stdImports, ...runtimeImports, ...imports);
|
|
187
|
+
context.anonymousObjectRecords.forEach((record) => {
|
|
188
|
+
lines.push('', ...emitRecord(record.name, record.properties, [], false, context));
|
|
189
|
+
});
|
|
190
|
+
context.objectRestRecords.forEach((record) => {
|
|
191
|
+
lines.push('', ...emitRecord(record.name, record.properties, [], false, context));
|
|
192
|
+
});
|
|
193
|
+
context.primitiveUnionEnums.forEach((union) => {
|
|
194
|
+
lines.push('', ...emitPrimitiveUnionEnumRust(union));
|
|
195
|
+
});
|
|
196
|
+
context.anonymousUnionEnums.forEach((union) => {
|
|
197
|
+
lines.push('', ...emitGeneralUnionRust(union.name, union.variants, union.typeParameters, true, context));
|
|
198
|
+
});
|
|
199
|
+
context.callableObjectRecords.forEach((record) => {
|
|
200
|
+
lines.push('', ...emitCallableObjectRecordRust(record, context));
|
|
201
|
+
});
|
|
202
|
+
declarations.forEach((declaration) => lines.push('', ...declaration));
|
|
203
|
+
return {
|
|
204
|
+
contents: lines.join('\n'),
|
|
205
|
+
path: getRustModuleFilePath(module, context.sourceModules),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function emitClass(declaration, context) {
|
|
209
|
+
// Rust has no inheritance of state, so a base that carries fields has nothing to inherit into. A
|
|
210
|
+
// stateless abstract base is a different thing: it is a set of methods, which is a trait, and the
|
|
211
|
+
// subclass implements it.
|
|
212
|
+
const abstractBase = getIrClassStatelessAbstractBaseRust(declaration, context);
|
|
213
|
+
const concreteBase = !abstractBase ? getIrClassConcreteBaseRust(declaration, context) : undefined;
|
|
214
|
+
if (declaration.extends && !abstractBase && !concreteBase) {
|
|
215
|
+
emissionError(context, `class ${declaration.binding.name} inheritance requires Rust ownership lowering`);
|
|
216
|
+
}
|
|
217
|
+
// An abstract class declares behaviour and holds no state, which is what a Rust trait is. A method
|
|
218
|
+
// it implements becomes the trait's default body, so a subclass inherits it by implementing nothing.
|
|
219
|
+
if (declaration.abstract)
|
|
220
|
+
return emitAbstractClassTraitRust(declaration, context);
|
|
221
|
+
const inheritedTraits = abstractBase ? [getBindingTargetNameRust(abstractBase.binding, context)] : [];
|
|
222
|
+
const implementedTraits = declaration.implements.map((reference) => {
|
|
223
|
+
if (reference.kind !== 'named' || reference.reference.kind !== 'binding') {
|
|
224
|
+
return emissionError(context, `class ${declaration.binding.name} implements a type with no Rust trait`);
|
|
225
|
+
}
|
|
226
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'interface' &&
|
|
227
|
+
reference.reference.kind === 'binding' &&
|
|
228
|
+
candidate.binding.id === reference.reference.binding.id);
|
|
229
|
+
if (!target) {
|
|
230
|
+
return emissionError(context, `class ${declaration.binding.name} implements an interface declared outside this module`);
|
|
231
|
+
}
|
|
232
|
+
return emitType(reference, context);
|
|
233
|
+
});
|
|
234
|
+
const compositionInit = concreteBase && declaration.classConstructor
|
|
235
|
+
? getIrClassCompositionConstructorRust(declaration, concreteBase)
|
|
236
|
+
: undefined;
|
|
237
|
+
const constructorFields = !concreteBase && declaration.classConstructor
|
|
238
|
+
? getIrClassConstructorFieldAssignmentsRust(declaration, abstractBase !== undefined)
|
|
239
|
+
: undefined;
|
|
240
|
+
if (declaration.classConstructor &&
|
|
241
|
+
!constructorFields &&
|
|
242
|
+
!compositionInit &&
|
|
243
|
+
(declaration.classConstructor.parameters.length > 0 || declaration.classConstructor.body.length > 0)) {
|
|
244
|
+
emissionError(context, `class ${declaration.binding.name} constructor requires Rust initialization lowering`);
|
|
245
|
+
}
|
|
246
|
+
// A static field is one value shared by the type, which Rust spells as an associated constant —
|
|
247
|
+
// but only where the source's initializer is a constant. Anything computed needs a place to run,
|
|
248
|
+
// and an associated constant has none.
|
|
249
|
+
const staticFields = declaration.fields.filter((field) => field.static);
|
|
250
|
+
if (staticFields.some((field) => field.initializer?.kind !== 'literal')) {
|
|
251
|
+
emissionError(context, `class ${declaration.binding.name} static fields require a constant initializer`);
|
|
252
|
+
}
|
|
253
|
+
const constructed = !declaration.classConstructor ||
|
|
254
|
+
(declaration.classConstructor.parameters.length === 0 && declaration.classConstructor.body.length === 0);
|
|
255
|
+
const instanceFields = declaration.fields.filter((field) => !field.static);
|
|
256
|
+
if (instanceFields.some((field) => field.initializer) && !constructed && !constructorFields && !compositionInit) {
|
|
257
|
+
emissionError(context, `class ${declaration.binding.name} field initializers require constructor lowering`);
|
|
258
|
+
}
|
|
259
|
+
if (instanceFields.some((field) => field.initializer) &&
|
|
260
|
+
instanceFields.some((field) => !field.initializer && !field.declare)) {
|
|
261
|
+
emissionError(context, `class ${declaration.binding.name} partially initializes its fields`);
|
|
262
|
+
}
|
|
263
|
+
const structVisibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
264
|
+
const lines = [
|
|
265
|
+
emitRustRecordDerive([...instanceFields.map((field) => field.type), ...(declaration.extends ? [declaration.extends] : [])], context),
|
|
266
|
+
`${structVisibility}struct ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeParameters(declaration.typeParameters, context)} {`,
|
|
267
|
+
];
|
|
268
|
+
if (concreteBase) {
|
|
269
|
+
lines.push(` ${safeRustValueName('base')}: ${getBindingTargetNameRust(concreteBase.binding, context)},`);
|
|
270
|
+
}
|
|
271
|
+
for (const field of instanceFields) {
|
|
272
|
+
lines.push(` ${field.visibility === 'public' ? 'pub ' : ''}${safeRustValueName(field.name)}: ${emitType(field.type, context)},`);
|
|
273
|
+
}
|
|
274
|
+
lines.push('}');
|
|
275
|
+
// A field initializer is a constructor obligation, and the neutral plan already decides when each
|
|
276
|
+
// field is initialized. Rust has no implicit constructor, so the plan becomes an associated `new`.
|
|
277
|
+
const initialization = instanceFields.every((field) => field.initializer || field.declare) && instanceFields.length > 0 && constructed
|
|
278
|
+
? createIrClassInitializationPlan(declaration)
|
|
279
|
+
: undefined;
|
|
280
|
+
const associated = staticFields.map((field) => ` ${field.visibility === 'public' ? 'pub ' : ''}const ${constantRustName(field.name)}: ${emitType(field.type, context)} = ${emitExpression(field.initializer, context)};`);
|
|
281
|
+
if (constructorFields && declaration.classConstructor) {
|
|
282
|
+
associated.push(` ${structVisibility}fn new(${declaration.classConstructor.parameters.map((parameter) => emitParameter(parameter, context)).join(', ')}) -> Self {`, ' Self {', ...constructorFields.map((field) => ` ${safeRustValueName(field.name)}: ${emitOwnedOperandRust(field.value, context)},`), ' }', ' }');
|
|
283
|
+
}
|
|
284
|
+
if (compositionInit && concreteBase && declaration.classConstructor) {
|
|
285
|
+
associated.push(` ${structVisibility}fn new(${declaration.classConstructor.parameters.map((parameter) => emitParameter(parameter, context)).join(', ')}) -> Self {`, ' Self {', ` ${safeRustValueName('base')}: ${getBindingTargetNameRust(concreteBase.binding, context)}::new(${compositionInit.superArguments.map((argument) => emitOwnedOperandRust(argument, context)).join(', ')}),`, ...compositionInit.childFields.map((field) => ` ${safeRustValueName(field.name)}: ${emitOwnedOperandRust(field.value, context)},`), ' }', ' }');
|
|
286
|
+
}
|
|
287
|
+
if (initialization) {
|
|
288
|
+
const instanceOrder = initialization.fields.filter((field) => declaration.fields[field.fieldIndex] && !declaration.fields[field.fieldIndex].static);
|
|
289
|
+
associated.push(` ${structVisibility}fn new() -> Self {`, ' Self {', ...instanceOrder.map((field) => {
|
|
290
|
+
const source = declaration.fields[field.fieldIndex];
|
|
291
|
+
if (source.declare)
|
|
292
|
+
return ` ${safeRustValueName(source.name)}: Default::default(),`;
|
|
293
|
+
return ` ${safeRustValueName(source.name)}: ${emitExpression(source.initializer, context)},`;
|
|
294
|
+
}), ' }', ' }');
|
|
295
|
+
}
|
|
296
|
+
const mutatingMethodNames = getIrClassMutatingMethodNamesRust(declaration);
|
|
297
|
+
// A trait's methods belong in its `impl` block, not in the inherent one, so the two are split by
|
|
298
|
+
// which trait declares each method name.
|
|
299
|
+
const traitMethodNames = new Map();
|
|
300
|
+
for (const reference of declaration.implements) {
|
|
301
|
+
if (reference.kind !== 'named' || reference.reference.kind !== 'binding')
|
|
302
|
+
continue;
|
|
303
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'interface' &&
|
|
304
|
+
reference.reference.kind === 'binding' &&
|
|
305
|
+
candidate.binding.id === reference.reference.binding.id);
|
|
306
|
+
if (target?.kind !== 'interface')
|
|
307
|
+
continue;
|
|
308
|
+
for (const property of target.properties)
|
|
309
|
+
traitMethodNames.set(property.name, emitType(reference, context));
|
|
310
|
+
}
|
|
311
|
+
const traitAbstractFields = new Map();
|
|
312
|
+
if (abstractBase) {
|
|
313
|
+
const traitName = getBindingTargetNameRust(abstractBase.binding, context);
|
|
314
|
+
for (const method of abstractBase.methods)
|
|
315
|
+
traitMethodNames.set(method.name, traitName);
|
|
316
|
+
const abstractFields = abstractBase.fields.filter((field) => field.abstract);
|
|
317
|
+
if (abstractFields.length > 0)
|
|
318
|
+
traitAbstractFields.set(traitName, abstractFields);
|
|
319
|
+
}
|
|
320
|
+
const traitDataProperties = new Map();
|
|
321
|
+
for (const reference of declaration.implements) {
|
|
322
|
+
if (reference.kind !== 'named' || reference.reference.kind !== 'binding')
|
|
323
|
+
continue;
|
|
324
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'interface' &&
|
|
325
|
+
reference.reference.kind === 'binding' &&
|
|
326
|
+
candidate.binding.id === reference.reference.binding.id);
|
|
327
|
+
if (target?.kind !== 'interface')
|
|
328
|
+
continue;
|
|
329
|
+
traitDataProperties.set(emitType(reference, context), target.properties.filter((property) => property.type.kind !== 'function'));
|
|
330
|
+
}
|
|
331
|
+
if (concreteBase) {
|
|
332
|
+
context.compositionBase = {
|
|
333
|
+
baseDeclaration: concreteBase,
|
|
334
|
+
fieldName: 'base',
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const inherentMethods = declaration.methods.filter((method) => !traitMethodNames.has(method.name));
|
|
338
|
+
const emitMethodLines = (method) => {
|
|
339
|
+
// Rust has no properties, so an accessor is a method. A setter takes the receiver mutably and is
|
|
340
|
+
// named apart from the getter, because Rust has one namespace for both and the source had two.
|
|
341
|
+
const target = getIrClassMethodTargetNameRust(method);
|
|
342
|
+
const receiver = method.accessor === 'set' || mutatingMethodNames.has(target) ? '&mut self' : '&self';
|
|
343
|
+
const parameters = [
|
|
344
|
+
...(method.static ? [] : [receiver]),
|
|
345
|
+
...method.parameters.map((parameter) => emitParameter(parameter, context)),
|
|
346
|
+
].join(', ');
|
|
347
|
+
// A setter yields nothing. The source wrote no return type and the neutral model kept that
|
|
348
|
+
// unknown, but the accessor contract already decides it.
|
|
349
|
+
const returns = method.accessor === 'set' ? '()' : emitType(method.returns, context);
|
|
350
|
+
return [
|
|
351
|
+
` ${method.visibility === 'public' && !traitMethodNames.has(method.name) ? 'pub ' : ''}fn ${target}${emitTypeParameters(method.typeParameters, context)}(${parameters}) -> ${returns} {`,
|
|
352
|
+
...indentSourceLines(emitStatements(method.body, context), 2),
|
|
353
|
+
' }',
|
|
354
|
+
];
|
|
355
|
+
};
|
|
356
|
+
for (const trait of [...inheritedTraits, ...implementedTraits]) {
|
|
357
|
+
const traitMethods = declaration.methods.filter((method) => traitMethodNames.get(method.name) === trait);
|
|
358
|
+
lines.push('', `impl${emitTypeParameters(declaration.typeParameters, context)} ${trait} for ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeArguments(declaration.typeParameters, context)} {`);
|
|
359
|
+
const traitAccessors = traitDataProperties.get(trait) ?? [];
|
|
360
|
+
const abstractFields = traitAbstractFields.get(trait) ?? [];
|
|
361
|
+
let emittedCount = 0;
|
|
362
|
+
abstractFields.forEach((field) => {
|
|
363
|
+
if (emittedCount > 0)
|
|
364
|
+
lines.push('');
|
|
365
|
+
const owned = isIrTypeCopyValueRust(field.type) ? '' : '.clone()';
|
|
366
|
+
lines.push(` fn ${safeRustValueName(field.name)}(&self) -> ${emitType(field.type, context)} {`, ` self.${safeRustValueName(field.name)}${owned}`, ' }');
|
|
367
|
+
emittedCount++;
|
|
368
|
+
});
|
|
369
|
+
traitMethods.forEach((method) => {
|
|
370
|
+
if (emittedCount > 0)
|
|
371
|
+
lines.push('');
|
|
372
|
+
lines.push(...emitMethodLines(method));
|
|
373
|
+
emittedCount++;
|
|
374
|
+
});
|
|
375
|
+
traitAccessors.forEach((property) => {
|
|
376
|
+
if (emittedCount > 0)
|
|
377
|
+
lines.push('');
|
|
378
|
+
lines.push(` fn ${safeRustValueName(property.name)}(&self) -> ${emitType(property.type, context)} {`, ` self.${safeRustValueName(property.name)}.clone()`, ' }');
|
|
379
|
+
emittedCount++;
|
|
380
|
+
});
|
|
381
|
+
lines.push('}');
|
|
382
|
+
}
|
|
383
|
+
if (inherentMethods.length > 0 || associated.length > 0) {
|
|
384
|
+
lines.push('', `impl${emitTypeParameters(declaration.typeParameters, context)} ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeArguments(declaration.typeParameters, context)} {`, ...associated);
|
|
385
|
+
inherentMethods.forEach((method, index) => {
|
|
386
|
+
if (index > 0 || associated.length > 0)
|
|
387
|
+
lines.push('');
|
|
388
|
+
lines.push(...emitMethodLines(method));
|
|
389
|
+
});
|
|
390
|
+
lines.push('}');
|
|
391
|
+
}
|
|
392
|
+
if (concreteBase) {
|
|
393
|
+
context.compositionBase = undefined;
|
|
394
|
+
}
|
|
395
|
+
return lines;
|
|
396
|
+
}
|
|
397
|
+
function emitDeclaration(declaration, context) {
|
|
398
|
+
switch (declaration.kind) {
|
|
399
|
+
case 'class':
|
|
400
|
+
return emitClass(declaration, context);
|
|
401
|
+
case 'enum':
|
|
402
|
+
return emitEnum(declaration, context);
|
|
403
|
+
case 'function':
|
|
404
|
+
return emitFunction(declaration, context);
|
|
405
|
+
case 'interface':
|
|
406
|
+
return emitInterface(declaration, context);
|
|
407
|
+
case 'typeAlias':
|
|
408
|
+
return emitTypeAlias(declaration, context);
|
|
409
|
+
case 'variable':
|
|
410
|
+
return emitVariableDeclaration(declaration, context);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function emitEnum(declaration, context) {
|
|
414
|
+
const values = declaration.members.map((member) => member.value);
|
|
415
|
+
const namespaceFunctions = getIrEnumNamespaceFunctionsRust(declaration, context.module);
|
|
416
|
+
if (namespaceFunctions.length > 0) {
|
|
417
|
+
if (values.some((value) => typeof value !== 'number' || !Number.isInteger(value))) {
|
|
418
|
+
emissionError(context, `enum ${declaration.binding.name} value namespace requires integer discriminants`);
|
|
419
|
+
}
|
|
420
|
+
if (values.some((value) => Number(value) < -2_147_483_648 || Number(value) > 2_147_483_647)) {
|
|
421
|
+
emissionError(context, `enum ${declaration.binding.name} has a discriminant outside the Rust i32 range`);
|
|
422
|
+
}
|
|
423
|
+
return emitNumericEnumNamespaceWrapperRust(declaration, namespaceFunctions, context);
|
|
424
|
+
}
|
|
425
|
+
if (values.every((value) => typeof value === 'string'))
|
|
426
|
+
return emitStringEnumRust(declaration, context);
|
|
427
|
+
if (values.some((value) => typeof value !== 'number' || !Number.isInteger(value))) {
|
|
428
|
+
emissionError(context, `enum ${declaration.binding.name} requires one discriminant domain for Rust`);
|
|
429
|
+
}
|
|
430
|
+
if (values.some((value) => Number(value) < -2_147_483_648 || Number(value) > 2_147_483_647)) {
|
|
431
|
+
emissionError(context, `enum ${declaration.binding.name} has a discriminant outside the Rust i32 range`);
|
|
432
|
+
}
|
|
433
|
+
const visibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
434
|
+
const lines = [
|
|
435
|
+
'#[derive(Clone, Copy, Debug, PartialEq, Eq)]',
|
|
436
|
+
'#[repr(i32)]',
|
|
437
|
+
`${visibility}enum ${getBindingTargetNameRust(declaration.binding, context)} {`,
|
|
438
|
+
];
|
|
439
|
+
declaration.members.forEach((member) => {
|
|
440
|
+
lines.push(` ${safeRustTypeName(member.name)} = ${String(member.value)},`);
|
|
441
|
+
});
|
|
442
|
+
lines.push('}');
|
|
443
|
+
return lines;
|
|
444
|
+
}
|
|
445
|
+
function getIrEnumNamespaceFunctionsRust(declaration, module) {
|
|
446
|
+
return module.declarations.filter((candidate) => candidate.kind === 'function' &&
|
|
447
|
+
candidate.namespaceMember?.kind === 'binding' &&
|
|
448
|
+
candidate.namespaceMember.binding.id === declaration.binding.id &&
|
|
449
|
+
candidate.namespaceMember.path.length === 1);
|
|
450
|
+
}
|
|
451
|
+
function emitNumericEnumNamespaceWrapperRust(declaration, namespaceFunctions, context) {
|
|
452
|
+
const name = getBindingTargetNameRust(declaration.binding, context);
|
|
453
|
+
const visibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
454
|
+
const lines = [
|
|
455
|
+
'#[derive(Clone, Copy, Debug, PartialEq, Eq)]',
|
|
456
|
+
`${visibility}struct ${name}(i32);`,
|
|
457
|
+
'',
|
|
458
|
+
`impl ${name} {`,
|
|
459
|
+
...declaration.members.map((member) => ` ${visibility}const ${safeRustTypeName(member.name)}: Self = Self(${String(member.value)});`),
|
|
460
|
+
];
|
|
461
|
+
for (const namespaceFunction of namespaceFunctions) {
|
|
462
|
+
lines.push('', ...indentSourceLines(emitEnumNamespaceFunctionRust(namespaceFunction, context)));
|
|
463
|
+
}
|
|
464
|
+
lines.push('}');
|
|
465
|
+
return lines;
|
|
466
|
+
}
|
|
467
|
+
function emitEnumNamespaceFunctionRust(declaration, outer) {
|
|
468
|
+
const context = {
|
|
469
|
+
...outer,
|
|
470
|
+
activeTypeParameters: declaration.typeParameters,
|
|
471
|
+
enclosingReturnType: declaration.returns,
|
|
472
|
+
returnsAbsent: hasIrTypeAbsentMember(declaration.returns),
|
|
473
|
+
};
|
|
474
|
+
if (declaration.async)
|
|
475
|
+
emissionError(context, 'async enum namespace functions require Rust task lowering');
|
|
476
|
+
return [
|
|
477
|
+
`pub fn ${safeRustValueName(declaration.binding.name)}${emitTypeParameters(declaration.typeParameters, context)}(${declaration.parameters.map((parameter) => emitParameter(parameter, context)).join(', ')}) -> ${emitType(declaration.returns, context)} {`,
|
|
478
|
+
...indentSourceLines(emitStatements(declaration.body, context)),
|
|
479
|
+
'}',
|
|
480
|
+
];
|
|
481
|
+
}
|
|
482
|
+
// Rust discriminants are integers, so a string enum keeps unit variants and carries its source
|
|
483
|
+
// values as an explicit mapping. Both directions are emitted because the source language treats the
|
|
484
|
+
// value as the enum: code compares against it and constructs from it.
|
|
485
|
+
function emitStringEnumRust(declaration, context) {
|
|
486
|
+
const name = getBindingTargetNameRust(declaration.binding, context);
|
|
487
|
+
const visibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
488
|
+
return [
|
|
489
|
+
'#[derive(Clone, Copy, Debug, PartialEq, Eq)]',
|
|
490
|
+
`${visibility}enum ${name} {`,
|
|
491
|
+
...declaration.members.map((member) => ` ${safeRustTypeName(member.name)},`),
|
|
492
|
+
'}',
|
|
493
|
+
'',
|
|
494
|
+
`impl ${name} {`,
|
|
495
|
+
` ${visibility}fn as_str(&self) -> &'static str {`,
|
|
496
|
+
' match self {',
|
|
497
|
+
...declaration.members.map((member) => ` ${name}::${safeRustTypeName(member.name)} => ${JSON.stringify(String(member.value))},`),
|
|
498
|
+
' }',
|
|
499
|
+
' }',
|
|
500
|
+
'',
|
|
501
|
+
` ${visibility}fn from_str(value: &str) -> Option<Self> {`,
|
|
502
|
+
' match value {',
|
|
503
|
+
...declaration.members.map((member) => ` ${JSON.stringify(String(member.value))} => Some(${name}::${safeRustTypeName(member.name)}),`),
|
|
504
|
+
' _ => None,',
|
|
505
|
+
' }',
|
|
506
|
+
' }',
|
|
507
|
+
'}',
|
|
508
|
+
];
|
|
509
|
+
}
|
|
510
|
+
function emitExpression(expression, context) {
|
|
511
|
+
switch (expression.kind) {
|
|
512
|
+
case 'array':
|
|
513
|
+
return `vec![${expression.elements.map((element) => (element ? emitOwnedOperandRust(element, context) : 'Default::default()')).join(', ')}]`;
|
|
514
|
+
case 'assignment': {
|
|
515
|
+
const typedArrayAssignment = emitTypedArrayElementAssignmentRust(expression, context);
|
|
516
|
+
if (typedArrayAssignment)
|
|
517
|
+
return typedArrayAssignment;
|
|
518
|
+
if (expression.left.kind === 'identifier' &&
|
|
519
|
+
expression.left.reference.kind === 'binding' &&
|
|
520
|
+
context.cellWrappedBindingIds.has(expression.left.reference.binding.id)) {
|
|
521
|
+
const name = emitIdentifierReferenceRust(expression.left.reference, context);
|
|
522
|
+
const right = emitExpression(expression.right, context);
|
|
523
|
+
if (expression.operator === '=')
|
|
524
|
+
return `${name}.set(${right})`;
|
|
525
|
+
if (expression.operator === '**=' &&
|
|
526
|
+
expression.semantics.left.flow === 'number' &&
|
|
527
|
+
expression.semantics.right.flow === 'number') {
|
|
528
|
+
return `${name}.set(f64::powf(${name}.get(), ${right}))`;
|
|
529
|
+
}
|
|
530
|
+
if (expression.operator === '>>>=' &&
|
|
531
|
+
expression.semantics.left.flow === 'number' &&
|
|
532
|
+
expression.semantics.right.flow === 'number') {
|
|
533
|
+
return `${name}.set(((((${name}.get() as i32) as u32) >> (${right} as u32)) as f64))`;
|
|
534
|
+
}
|
|
535
|
+
if ((expression.operator === '&=' ||
|
|
536
|
+
expression.operator === '|=' ||
|
|
537
|
+
expression.operator === '^=' ||
|
|
538
|
+
expression.operator === '<<=' ||
|
|
539
|
+
expression.operator === '>>=') &&
|
|
540
|
+
expression.semantics.left.flow === 'number' &&
|
|
541
|
+
expression.semantics.right.flow === 'number') {
|
|
542
|
+
const binaryOp = expression.operator.slice(0, -1);
|
|
543
|
+
return `${name}.set((((${name}.get() as i32) ${binaryOp} (${right} as i32)) as f64))`;
|
|
544
|
+
}
|
|
545
|
+
if (expression.operator === '||=' || expression.operator === '&&=') {
|
|
546
|
+
if (expression.semantics.left.flow === 'boolean') {
|
|
547
|
+
const condition = expression.operator === '||=' ? `!${name}.get()` : `${name}.get()`;
|
|
548
|
+
return `{ if ${condition} { ${name}.set(${right}); } ${name}.get() }`;
|
|
549
|
+
}
|
|
550
|
+
if (expression.semantics.left.flow === 'number') {
|
|
551
|
+
const condition = expression.operator === '||='
|
|
552
|
+
? `${name}.get() == 0.0 || ${name}.get().is_nan()`
|
|
553
|
+
: `${name}.get() != 0.0 && !${name}.get().is_nan()`;
|
|
554
|
+
return `{ if ${condition} { ${name}.set(${right}); } ${name}.get() }`;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (expression.operator === '??=') {
|
|
558
|
+
if (context.nullableBindingIds.has(expression.left.reference.binding.id) &&
|
|
559
|
+
(expression.semantics.right.flow === 'number' || expression.semantics.right.flow === 'boolean')) {
|
|
560
|
+
return `{ if ${name}.get().is_none() { ${name}.set(Some(${right})); } ${name}.get().clone().unwrap() }`;
|
|
561
|
+
}
|
|
562
|
+
emissionError(context, `operator ${expression.operator} on ${expression.semantics.left.flow} and ${expression.semantics.right.flow} requires Rust type-directed lowering`);
|
|
563
|
+
}
|
|
564
|
+
if (!isAssignmentOperatorDirectRust(expression.operator, expression.semantics)) {
|
|
565
|
+
emissionError(context, `operator ${expression.operator} on ${expression.semantics.left.flow} and ${expression.semantics.right.flow} requires Rust type-directed lowering`);
|
|
566
|
+
}
|
|
567
|
+
const op = expression.operator.slice(0, -1);
|
|
568
|
+
return `${name}.set(${name}.get() ${op} ${normalizeSourceTextGrouping(right)})`;
|
|
569
|
+
}
|
|
570
|
+
if (expression.left.kind === 'identifier' &&
|
|
571
|
+
expression.left.reference.kind === 'binding' &&
|
|
572
|
+
context.refCellWrappedBindingIds.has(expression.left.reference.binding.id)) {
|
|
573
|
+
const name = emitIdentifierReferenceRust(expression.left.reference, context);
|
|
574
|
+
const right = emitExpression(expression.right, context);
|
|
575
|
+
if (expression.operator === '=')
|
|
576
|
+
return `${name}.replace(${right})`;
|
|
577
|
+
if (expression.operator === '??=') {
|
|
578
|
+
if (context.nullableBindingIds.has(expression.left.reference.binding.id)) {
|
|
579
|
+
return `{ if ${name}.borrow().is_none() { *${name}.borrow_mut() = Some(${right}); } ${name}.borrow().clone().unwrap() }`;
|
|
580
|
+
}
|
|
581
|
+
emissionError(context, 'operator ??= on ref-cell-wrapped binding requires a nullable Rust target');
|
|
582
|
+
}
|
|
583
|
+
emissionError(context, `operator ${expression.operator} on non-Copy ref-cell-wrapped binding requires Rust type-directed lowering`);
|
|
584
|
+
}
|
|
585
|
+
if (expression.operator === '=' &&
|
|
586
|
+
expression.left.kind === 'property' &&
|
|
587
|
+
getIrExpressionClassAccessorRust(expression.left.object, expression.left.name, 'set', context)) {
|
|
588
|
+
return `${emitExpression(expression.left.object, context)}.set_${safeRustValueName(expression.left.name)}(${emitOwnedOperandRust(expression.right, context)})`;
|
|
589
|
+
}
|
|
590
|
+
if (expression.operator === '+=' &&
|
|
591
|
+
expression.semantics.left.flow === 'string' &&
|
|
592
|
+
expression.semantics.right.flow === 'string') {
|
|
593
|
+
const left = emitExpression(expression.left, context);
|
|
594
|
+
const right = emitExpression(expression.right, context);
|
|
595
|
+
return `${left}.push_str(&${normalizeSourceTextGrouping(right)})`;
|
|
596
|
+
}
|
|
597
|
+
if ((expression.operator === '&=' ||
|
|
598
|
+
expression.operator === '|=' ||
|
|
599
|
+
expression.operator === '^=' ||
|
|
600
|
+
expression.operator === '<<=' ||
|
|
601
|
+
expression.operator === '>>=') &&
|
|
602
|
+
expression.semantics.left.flow === 'number' &&
|
|
603
|
+
expression.semantics.right.flow === 'number') {
|
|
604
|
+
const left = emitExpression(expression.left, context);
|
|
605
|
+
const right = emitExpression(expression.right, context);
|
|
606
|
+
const binaryOp = expression.operator.slice(0, -1);
|
|
607
|
+
return `${left} = (((${left} as i32) ${binaryOp} (${right} as i32)) as f64)`;
|
|
608
|
+
}
|
|
609
|
+
if (expression.operator === '**=' &&
|
|
610
|
+
expression.semantics.left.flow === 'number' &&
|
|
611
|
+
expression.semantics.right.flow === 'number') {
|
|
612
|
+
const left = emitExpression(expression.left, context);
|
|
613
|
+
const right = emitExpression(expression.right, context);
|
|
614
|
+
return `${left} = f64::powf(${left}, ${right})`;
|
|
615
|
+
}
|
|
616
|
+
if (expression.operator === '>>>=' &&
|
|
617
|
+
expression.semantics.left.flow === 'number' &&
|
|
618
|
+
expression.semantics.right.flow === 'number') {
|
|
619
|
+
const left = emitExpression(expression.left, context);
|
|
620
|
+
const right = emitExpression(expression.right, context);
|
|
621
|
+
return `${left} = ((((${left} as i32) as u32) >> (${right} as u32)) as f64)`;
|
|
622
|
+
}
|
|
623
|
+
if (expression.operator === '||=' || expression.operator === '&&=') {
|
|
624
|
+
const left = emitExpression(expression.left, context);
|
|
625
|
+
const right = emitExpression(expression.right, context);
|
|
626
|
+
if (expression.semantics.left.flow === 'boolean') {
|
|
627
|
+
const condition = expression.operator === '||=' ? `!${left}` : left;
|
|
628
|
+
return `{ if ${condition} { ${left} = ${right}; } ${left} }`;
|
|
629
|
+
}
|
|
630
|
+
if (expression.semantics.left.flow === 'number') {
|
|
631
|
+
const condition = expression.operator === '||='
|
|
632
|
+
? `${left} == 0.0 || ${left}.is_nan()`
|
|
633
|
+
: `${left} != 0.0 && !${left}.is_nan()`;
|
|
634
|
+
return `{ if ${condition} { ${left} = ${right}; } ${left} }`;
|
|
635
|
+
}
|
|
636
|
+
if (expression.semantics.left.flow === 'string') {
|
|
637
|
+
const condition = expression.operator === '||=' ? `${left}.is_empty()` : `!${left}.is_empty()`;
|
|
638
|
+
return `{ if ${condition} { ${left} = ${right}; } ${left} }`;
|
|
639
|
+
}
|
|
640
|
+
emissionError(context, `operator ${expression.operator} on ${expression.semantics.left.flow} requires Rust semantic lowering`);
|
|
641
|
+
}
|
|
642
|
+
if (expression.operator === '??=') {
|
|
643
|
+
const left = emitExpression(expression.left, context);
|
|
644
|
+
const right = emitExpression(expression.right, context);
|
|
645
|
+
if (expression.left.kind === 'identifier' &&
|
|
646
|
+
expression.left.reference.kind === 'binding' &&
|
|
647
|
+
context.nullableBindingIds.has(expression.left.reference.binding.id)) {
|
|
648
|
+
return `{ if ${left}.is_none() { ${left} = Some(${right}); } ${left}.clone().unwrap() }`;
|
|
649
|
+
}
|
|
650
|
+
emissionError(context, 'operator ??= requires a nullable Rust target');
|
|
651
|
+
}
|
|
652
|
+
if (expression.operator === '=' &&
|
|
653
|
+
expression.left.kind === 'identifier' &&
|
|
654
|
+
expression.left.reference.kind === 'binding') {
|
|
655
|
+
const targetType = context.bindingTypes.get(expression.left.reference.binding.id);
|
|
656
|
+
const dualSentinelUnion = targetType ? resolveDualSentinelUnionEnumRust(targetType, context) : undefined;
|
|
657
|
+
if (dualSentinelUnion) {
|
|
658
|
+
const wrapped = emitDualSentinelUnionConstructionRust(expression.right, dualSentinelUnion, context);
|
|
659
|
+
if (wrapped)
|
|
660
|
+
return `${emitExpression(expression.left, context)} = ${wrapped}`;
|
|
661
|
+
}
|
|
662
|
+
const enumName = context.primitiveUnionBindingIds.get(expression.left.reference.binding.id);
|
|
663
|
+
if (enumName) {
|
|
664
|
+
const targetEnum = [...context.primitiveUnionEnums.values()].find((e) => e.name === enumName);
|
|
665
|
+
if (targetEnum) {
|
|
666
|
+
const wrapped = emitPrimitiveUnionConstructionRust(expression.right, targetEnum, context);
|
|
667
|
+
if (wrapped) {
|
|
668
|
+
return `${emitExpression(expression.left, context)} = ${wrapped}`;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
const left = emitExpression(expression.left, context);
|
|
674
|
+
const right = emitOptionalTargetOperandRust(expression.left, expression.right, context);
|
|
675
|
+
return `${left} ${emitAssignmentOperatorRust(expression.operator, expression.semantics, context)} ${normalizeSourceTextGrouping(right)}`;
|
|
676
|
+
}
|
|
677
|
+
case 'await':
|
|
678
|
+
// `.await` consumes the future it is given, while the source language's await does not consume
|
|
679
|
+
// the promise: a promise settles once and every await sees that settlement. A task reached more
|
|
680
|
+
// than once is therefore cloned, which the runtime contract's first-call-wins settlement is
|
|
681
|
+
// what makes equivalent.
|
|
682
|
+
return `${emitOwnedOperandRust(expression.expression, context)}.await`;
|
|
683
|
+
case 'binary': {
|
|
684
|
+
if (expression.semantics.nullishComparison) {
|
|
685
|
+
const evidence = expression.semantics.nullishComparison;
|
|
686
|
+
// A single absent member uses `Option`. When both source sentinels are possible the binding
|
|
687
|
+
// instead carries a generated enum, so strict comparison selects one unit variant while
|
|
688
|
+
// loose comparison deliberately accepts either.
|
|
689
|
+
if (evidence.admitsNull && evidence.admitsUndefined) {
|
|
690
|
+
const operand = expression.left.kind === 'identifier' && expression.left.reference.kind === 'ambient'
|
|
691
|
+
? expression.right
|
|
692
|
+
: expression.left;
|
|
693
|
+
const union = getIrExpressionDualSentinelUnionRust(operand, context);
|
|
694
|
+
if (!union) {
|
|
695
|
+
emissionError(context, 'dual-sentinel nullish comparison requires Rust union representation evidence');
|
|
696
|
+
}
|
|
697
|
+
const strict = expression.operator === '===' || expression.operator === '!==';
|
|
698
|
+
const patterns = strict
|
|
699
|
+
? [`${union.name}::${evidence.literal === 'null' ? 'Null' : 'Undefined'}`]
|
|
700
|
+
: [`${union.name}::Null`, `${union.name}::Undefined`];
|
|
701
|
+
const test = `matches!(&${emitExpression(operand, context)}, ${patterns.join(' | ')})`;
|
|
702
|
+
return expression.operator === '!=' || expression.operator === '!==' ? `!${test}` : test;
|
|
703
|
+
}
|
|
704
|
+
const operand = expression.left.kind === 'identifier' && expression.left.reference.kind === 'ambient'
|
|
705
|
+
? expression.right
|
|
706
|
+
: expression.left;
|
|
707
|
+
const negated = expression.operator === '!=' || expression.operator === '!==';
|
|
708
|
+
return `${emitExpression(operand, context)}.${negated ? 'is_some' : 'is_none'}()`;
|
|
709
|
+
}
|
|
710
|
+
if (expression.operator === '??') {
|
|
711
|
+
// Rust has no `??`. The shape is `Option::unwrap_or_else`, which needs the left operand to
|
|
712
|
+
// already be an Option — an optional chain produces one, an ordinary value does not.
|
|
713
|
+
// A coalesce whose left cannot be absent is its left: the default is unreachable, and the
|
|
714
|
+
// source's own types are what say so.
|
|
715
|
+
if (expression.left.kind === 'property' && expression.left.optionalChain?.receiverNullish === 'excluded') {
|
|
716
|
+
return emitExpression(expression.left, context);
|
|
717
|
+
}
|
|
718
|
+
if (!isIrExpressionOptionShapedRust(expression.left, context)) {
|
|
719
|
+
emissionError(context, 'operator ?? requires an Option-shaped left operand for Rust');
|
|
720
|
+
}
|
|
721
|
+
return `${emitOptionShapedOperandRust(expression.left, context)}.unwrap_or_else(|| ${emitExpression(expression.right, context)})`;
|
|
722
|
+
}
|
|
723
|
+
if (expression.operator === '+' &&
|
|
724
|
+
expression.semantics.left.flow === 'string' &&
|
|
725
|
+
expression.semantics.right.flow === 'string') {
|
|
726
|
+
return emitStringConcatenationRust(expression, context);
|
|
727
|
+
}
|
|
728
|
+
if ((expression.operator === '==' ||
|
|
729
|
+
expression.operator === '===' ||
|
|
730
|
+
expression.operator === '!=' ||
|
|
731
|
+
expression.operator === '!==') &&
|
|
732
|
+
((isIrExpressionTypedArrayRust(expression.left, context) &&
|
|
733
|
+
isIrExpressionTypedArrayRust(expression.right, context)) ||
|
|
734
|
+
(isIrExpressionDataViewRust(expression.left, context) &&
|
|
735
|
+
isIrExpressionDataViewRust(expression.right, context)) ||
|
|
736
|
+
(isIrExpressionArrayBufferRust(expression.left, context) &&
|
|
737
|
+
isIrExpressionArrayBufferRust(expression.right, context)))) {
|
|
738
|
+
const operator = expression.operator === '!=' || expression.operator === '!==' ? '!=' : '==';
|
|
739
|
+
return `(${emitExpression(expression.left, context)} ${operator} ${emitExpression(expression.right, context)})`;
|
|
740
|
+
}
|
|
741
|
+
const typeofTest = getTypeofTypeTestRust(expression, context);
|
|
742
|
+
if (typeofTest) {
|
|
743
|
+
const operand = emitExpression(typeofTest.operand, context);
|
|
744
|
+
const test = `matches!(${operand}, ${typeofTest.enumName}::${typeofTest.variantName}(_))`;
|
|
745
|
+
return typeofTest.negated ? `!${test}` : test;
|
|
746
|
+
}
|
|
747
|
+
if (expression.operator === '**' &&
|
|
748
|
+
expression.semantics.left.flow === 'number' &&
|
|
749
|
+
expression.semantics.right.flow === 'number') {
|
|
750
|
+
const left = emitExpression(expression.left, context);
|
|
751
|
+
const right = emitExpression(expression.right, context);
|
|
752
|
+
return `f64::powf(${left}, ${right})`;
|
|
753
|
+
}
|
|
754
|
+
if (expression.operator === '>>>' &&
|
|
755
|
+
expression.semantics.left.flow === 'number' &&
|
|
756
|
+
expression.semantics.right.flow === 'number') {
|
|
757
|
+
const left = emitExpression(expression.left, context);
|
|
758
|
+
const right = emitExpression(expression.right, context);
|
|
759
|
+
return `((((${left} as i32) as u32) >> (${right} as u32)) as f64)`;
|
|
760
|
+
}
|
|
761
|
+
const op = emitBinaryOperatorRust(expression.operator, expression.semantics, context);
|
|
762
|
+
const bitwise = expression.operator === '&' ||
|
|
763
|
+
expression.operator === '|' ||
|
|
764
|
+
expression.operator === '^' ||
|
|
765
|
+
expression.operator === '<<' ||
|
|
766
|
+
expression.operator === '>>';
|
|
767
|
+
const left = emitNumericEnumOperandRust(expression.left, context);
|
|
768
|
+
const right = emitNumericEnumOperandRust(expression.right, context);
|
|
769
|
+
if (bitwise)
|
|
770
|
+
return `(((${left} as i32) ${op} (${right} as i32)) as f64)`;
|
|
771
|
+
return `(${left} ${op} ${right})`;
|
|
772
|
+
}
|
|
773
|
+
case 'call':
|
|
774
|
+
if (expression.semantics.statementValue)
|
|
775
|
+
return emitStatementValueExpressionRust(expression, context);
|
|
776
|
+
if (expression.optional)
|
|
777
|
+
return emitOptionalCallExpressionRust(expression, context);
|
|
778
|
+
// Rust joins a slice of strings with a borrowed separator, while the source hands it an owned
|
|
779
|
+
// one. The separator is the only argument, so the borrow is decided here rather than by a
|
|
780
|
+
// general rule about where an owned string may stand.
|
|
781
|
+
if (expression.callee.kind === 'property' &&
|
|
782
|
+
expression.callee.member?.receiver === 'array' &&
|
|
783
|
+
expression.callee.member.name === 'join') {
|
|
784
|
+
const separator = expression.arguments[0];
|
|
785
|
+
if (expression.arguments.length !== 1 || !separator) {
|
|
786
|
+
emissionError(context, 'joining a collection requires exactly one separator argument');
|
|
787
|
+
}
|
|
788
|
+
return `${emitExpression(expression.callee.object, context)}.join(${emitBorrowedTextRust(separator, context)})`;
|
|
789
|
+
}
|
|
790
|
+
// Typed arrays use runtime views rather than Vec: slice copies storage, while subarray creates
|
|
791
|
+
// a distinct view sharing storage. Their bounds stay numeric until the runtime applies source
|
|
792
|
+
// relative-index rules (including negative and infinite bounds).
|
|
793
|
+
if (expression.callee.kind === 'property' &&
|
|
794
|
+
expression.callee.member?.receiver === 'typedArray' &&
|
|
795
|
+
(expression.callee.member.name === 'slice' || expression.callee.member.name === 'subarray')) {
|
|
796
|
+
if (expression.arguments.length > 2) {
|
|
797
|
+
emissionError(context, `${expression.callee.member.name} on a typed array takes at most a start and an end`);
|
|
798
|
+
}
|
|
799
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
800
|
+
const method = expression.callee.member.name;
|
|
801
|
+
if (expression.arguments.length === 0)
|
|
802
|
+
return `${receiver}.${method}(0.0)`;
|
|
803
|
+
const start = emitExpression(expression.arguments[0], context);
|
|
804
|
+
if (expression.arguments.length === 1)
|
|
805
|
+
return `${receiver}.${method}(${start})`;
|
|
806
|
+
return `${receiver}.${method}_range(${start}, ${emitExpression(expression.arguments[1], context)})`;
|
|
807
|
+
}
|
|
808
|
+
if (expression.semantics.typedArraySet) {
|
|
809
|
+
assertOneIrTypedArrayReceiverRust(expression.semantics.typedArraySet.receivers, context);
|
|
810
|
+
if (expression.callee.kind !== 'property' ||
|
|
811
|
+
expression.arguments.length < 1 ||
|
|
812
|
+
expression.arguments.length > 2) {
|
|
813
|
+
emissionError(context, 'setting a typed array requires a source and an optional offset');
|
|
814
|
+
}
|
|
815
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
816
|
+
const source = emitOwnedOperandRust(expression.arguments[0], context);
|
|
817
|
+
const offset = expression.arguments[1] ? emitExpression(expression.arguments[1], context) : '0.0';
|
|
818
|
+
return `${receiver}.copy_from(${source}, ${offset})`;
|
|
819
|
+
}
|
|
820
|
+
// An ordinary array slice is a Rust range copied back into an owned Vec.
|
|
821
|
+
if (expression.callee.kind === 'property' &&
|
|
822
|
+
expression.callee.member?.receiver === 'array' &&
|
|
823
|
+
expression.callee.member.name === 'slice') {
|
|
824
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
825
|
+
if (expression.arguments.length === 0)
|
|
826
|
+
return `${receiver}.clone()`;
|
|
827
|
+
if (expression.arguments.length > 2) {
|
|
828
|
+
emissionError(context, 'slicing a collection takes at most a start and an end');
|
|
829
|
+
}
|
|
830
|
+
const bounds = expression.arguments
|
|
831
|
+
.map((argument) => `${emitExpression(argument, context)} as usize`)
|
|
832
|
+
.join('..');
|
|
833
|
+
return `${receiver}[${expression.arguments.length === 1 ? `${bounds}..` : bounds}].to_vec()`;
|
|
834
|
+
}
|
|
835
|
+
if (expression.callee.kind === 'property' &&
|
|
836
|
+
expression.callee.member?.receiver === 'array' &&
|
|
837
|
+
expression.callee.member.name === 'concat' &&
|
|
838
|
+
expression.arguments.length === 1) {
|
|
839
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
840
|
+
const other = emitExpression(expression.arguments[0], context);
|
|
841
|
+
return `{ let mut __concat = ${receiver}; __concat.extend(${other}); __concat }`;
|
|
842
|
+
}
|
|
843
|
+
if (expression.callee.kind === 'property' &&
|
|
844
|
+
expression.callee.member?.receiver === 'string' &&
|
|
845
|
+
expression.callee.member.name === 'charAt' &&
|
|
846
|
+
expression.arguments.length === 1) {
|
|
847
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
848
|
+
const index = emitExpression(expression.arguments[0], context);
|
|
849
|
+
return `${receiver}.chars().nth(${index} as usize).map(|c| c.to_string()).unwrap_or_default()`;
|
|
850
|
+
}
|
|
851
|
+
if (expression.callee.kind === 'property' &&
|
|
852
|
+
expression.callee.member?.receiver === 'string' &&
|
|
853
|
+
expression.callee.member.name === 'charCodeAt' &&
|
|
854
|
+
expression.arguments.length === 1) {
|
|
855
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
856
|
+
const index = emitExpression(expression.arguments[0], context);
|
|
857
|
+
return `${receiver}.chars().nth(${index} as usize).map(|c| c as u32 as f64).unwrap_or(f64::NAN)`;
|
|
858
|
+
}
|
|
859
|
+
if (expression.callee.kind === 'property' &&
|
|
860
|
+
expression.callee.member?.receiver === 'string' &&
|
|
861
|
+
expression.callee.member.name === 'substring') {
|
|
862
|
+
const receiver = emitExpression(expression.callee.object, context);
|
|
863
|
+
if (expression.arguments.length === 0 || expression.arguments.length > 2) {
|
|
864
|
+
emissionError(context, 'string substring takes a start index and an optional end index');
|
|
865
|
+
}
|
|
866
|
+
const bounds = expression.arguments
|
|
867
|
+
.map((argument) => `${emitExpression(argument, context)} as usize`)
|
|
868
|
+
.join('..');
|
|
869
|
+
return `${receiver}[${expression.arguments.length === 1 ? `${bounds}..` : bounds}].to_string()`;
|
|
870
|
+
}
|
|
871
|
+
if (expression.callee.kind === 'property' && expression.callee.member) {
|
|
872
|
+
const binding = getCompilerRustAmbientMemberBinding(expression.callee.member);
|
|
873
|
+
if (binding && binding.kind !== 'countingMethod' && binding.kind !== 'propertyMethod') {
|
|
874
|
+
const receiver = emitPrimitiveUnionNarrowedReceiverRust(expression.callee.object, context) ??
|
|
875
|
+
emitExpression(expression.callee.object, context);
|
|
876
|
+
const borrows = binding.kind === 'borrowedMethod' || binding.kind === 'sentinelSearch' || binding.kind === 'splitCollect';
|
|
877
|
+
const values = expression.callee.member.receiver === 'dataView'
|
|
878
|
+
? emitCallArgumentsRust(expression, context)
|
|
879
|
+
: expression.arguments.map((argument) => borrows ? emitBorrowedTextRust(argument, context) : emitExpression(argument, context));
|
|
880
|
+
if (binding.kind === 'runtimeMethod') {
|
|
881
|
+
const target = recordRuntimeTypeRust(binding.targetName, context);
|
|
882
|
+
return `${target}(&${receiver}${values.length > 0 ? `, ${values.join(', ')}` : ''})`;
|
|
883
|
+
}
|
|
884
|
+
if (binding.kind === 'predicatePosition') {
|
|
885
|
+
return emitArrayPredicatePositionRust(receiver, expression.arguments[0], values[0], binding.targetName, context);
|
|
886
|
+
}
|
|
887
|
+
if (binding.kind === 'iterator') {
|
|
888
|
+
const firstArg = expression.arguments[0];
|
|
889
|
+
const closure = binding.borrowsElement
|
|
890
|
+
? emitBorrowedElementClosureRust(firstArg, context)
|
|
891
|
+
: firstArg && firstArg.kind !== 'function'
|
|
892
|
+
? emitIteratorCallbackWrapperRust(firstArg, values[0], context)
|
|
893
|
+
: values[0];
|
|
894
|
+
const ordered = binding.argumentOrder
|
|
895
|
+
? binding.argumentOrder.map((position) => values[position] ?? '')
|
|
896
|
+
: [closure ?? ''];
|
|
897
|
+
return `${receiver}.into_iter().${binding.targetName}(${ordered.join(', ')})${binding.collect ? '.collect::<Vec<_>>()' : ''}`;
|
|
898
|
+
}
|
|
899
|
+
if (binding.kind === 'positionSearch') {
|
|
900
|
+
const borrowed = expression.arguments.map((argument) => emitBorrowedTextRust(argument, context));
|
|
901
|
+
return `${receiver}.iter().${binding.targetName}(|x| x == ${borrowed.join(', ')}).map(|i| i as f64).unwrap_or(-1.0)`;
|
|
902
|
+
}
|
|
903
|
+
if (binding.kind === 'sentinelSearch') {
|
|
904
|
+
return `${receiver}.${binding.targetName}(${values.join(', ')}).map(|i| i as f64).unwrap_or(-1.0)`;
|
|
905
|
+
}
|
|
906
|
+
if (binding.kind === 'splitCollect') {
|
|
907
|
+
return `${receiver}.${binding.targetName}(${values.join(', ')}).map(|s| s.to_string()).collect::<Vec<String>>()`;
|
|
908
|
+
}
|
|
909
|
+
if (binding.kind === 'optionalLookup') {
|
|
910
|
+
const borrowed = expression.arguments.map((argument) => emitBorrowedTextRust(argument, context));
|
|
911
|
+
return `${receiver}.${binding.targetName}(${borrowed.join(', ')}).cloned()`;
|
|
912
|
+
}
|
|
913
|
+
const leading = binding.kind === 'method' ? (binding.leadingArguments ?? []) : [];
|
|
914
|
+
const trailing = binding.kind === 'borrowedMethod' ? (binding.trailingArguments ?? []) : [];
|
|
915
|
+
return `${receiver}.${binding.targetName}(${[...leading, ...values, ...trailing].join(', ')})${binding.owns ? '.to_owned()' : ''}`;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (expression.arguments.length === 1 &&
|
|
919
|
+
expression.arguments[0].kind === 'spread' &&
|
|
920
|
+
expression.callee.kind === 'property' &&
|
|
921
|
+
expression.callee.object.kind === 'identifier' &&
|
|
922
|
+
expression.callee.object.reference.kind === 'ambient' &&
|
|
923
|
+
expression.callee.object.reference.name === 'Math') {
|
|
924
|
+
const foldTarget = rustMathSpreadFoldTargets[expression.callee.name];
|
|
925
|
+
if (foldTarget) {
|
|
926
|
+
const spreadOperand = emitExpression(expression.arguments[0].expression, context);
|
|
927
|
+
return `${spreadOperand}.iter().cloned().fold(${foldTarget.identity}, ${foldTarget.folder})`;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
if (expression.callee.kind === 'identifier' &&
|
|
931
|
+
expression.callee.reference.kind === 'ambient' &&
|
|
932
|
+
expression.callee.reference.name === 'String' &&
|
|
933
|
+
expression.arguments.length === 1) {
|
|
934
|
+
const operand = emitExpression(expression.arguments[0], context);
|
|
935
|
+
return operand.startsWith('*') ? `(${operand}).to_string()` : `${operand}.to_string()`;
|
|
936
|
+
}
|
|
937
|
+
return `${expression.callee.kind === 'function' ? `(${emitExpression(expression.callee, context)})` : emitExpression(expression.callee, context)}(${emitCallArgumentsRust(expression, context).join(', ')})`;
|
|
938
|
+
case 'cast': {
|
|
939
|
+
const assertedUnknownType = expression.expression.kind === 'identifier' && expression.expression.reference.kind === 'binding'
|
|
940
|
+
? context.assertedUnknownBindingTypes.get(expression.expression.reference.binding.id)
|
|
941
|
+
: undefined;
|
|
942
|
+
if (assertedUnknownType &&
|
|
943
|
+
expression.expression.kind === 'identifier' &&
|
|
944
|
+
expression.expression.reference.kind === 'binding' &&
|
|
945
|
+
areIrAssertedUnknownRepresentationsEqualRust(assertedUnknownType, expression.type)) {
|
|
946
|
+
return emitOwnedOperandRust(expression.expression, context);
|
|
947
|
+
}
|
|
948
|
+
const unionCast = emitPrimitiveUnionCastRust(expression, context);
|
|
949
|
+
if (unionCast)
|
|
950
|
+
return unionCast;
|
|
951
|
+
if (!isIrCastTargetNumericRust(expression.type)) {
|
|
952
|
+
emissionError(context, `cast to ${expression.type.kind} requires Rust type-directed lowering`);
|
|
953
|
+
}
|
|
954
|
+
return `(${emitExpression(expression.expression, context)} as ${emitType(expression.type, context)})`;
|
|
955
|
+
}
|
|
956
|
+
case 'conditional':
|
|
957
|
+
return `if ${emitExpression(expression.condition, context)} { ${emitExpression(expression.whenTrue, context)} } else { ${emitExpression(expression.whenFalse, context)} }`;
|
|
958
|
+
case 'element':
|
|
959
|
+
if (expression.optional)
|
|
960
|
+
return emitOptionalElementExpressionRust(expression, context);
|
|
961
|
+
{
|
|
962
|
+
const closedSelection = emitClosedKeyElementSelectionRust(expression, context);
|
|
963
|
+
if (closedSelection)
|
|
964
|
+
return closedSelection;
|
|
965
|
+
}
|
|
966
|
+
if (expression.semantics.receivers.includes('object')) {
|
|
967
|
+
emissionError(context, 'computed object access requires JavaScript property-key coercion lowering');
|
|
968
|
+
}
|
|
969
|
+
if (expression.semantics.receivers.includes('tuple')) {
|
|
970
|
+
const index = getElementAccessTupleIndexRust(expression, context);
|
|
971
|
+
return `${emitExpression(expression.object, context)}.${String(index)}`;
|
|
972
|
+
}
|
|
973
|
+
if (hasOnlyIrTypedArrayReceiversRust(expression.semantics.receivers)) {
|
|
974
|
+
assertOneIrTypedArrayReceiverRust(expression.semantics.receivers, context);
|
|
975
|
+
return `${emitExpression(expression.object, context)}.get_index(${emitNumericEnumOperandRust(expression.index, context)})`;
|
|
976
|
+
}
|
|
977
|
+
// A written index is already a whole number; sending it through the neutral numeric type and
|
|
978
|
+
// back is noise the source never asked for.
|
|
979
|
+
return `${emitExpression(expression.object, context)}[${emitIndexOperandRust(expression.index, context)}]`;
|
|
980
|
+
case 'function':
|
|
981
|
+
if (expression.async)
|
|
982
|
+
emissionError(context, 'async closures require Flight task lowering');
|
|
983
|
+
if (expression.typeParameters.length > 0)
|
|
984
|
+
emissionError(context, 'generic closures require monomorphization');
|
|
985
|
+
return expression.expression
|
|
986
|
+
? `|${expression.parameters.map((parameter) => getBindingTargetNameRust(parameter.binding, context)).join(', ')}| ${normalizeSourceTextGrouping(emitExpression(expression.expression, context))}`
|
|
987
|
+
: `|${expression.parameters.map((parameter) => getBindingTargetNameRust(parameter.binding, context)).join(', ')}| {\n${indentSourceLines(emitStatements(expression.body, context)).join('\n')}\n}`;
|
|
988
|
+
case 'identifier': {
|
|
989
|
+
if (expression.reference.kind === 'binding' && context.cellWrappedBindingIds.has(expression.reference.binding.id))
|
|
990
|
+
return `${emitIdentifierReferenceRust(expression.reference, context)}.get()`;
|
|
991
|
+
if (expression.reference.kind === 'binding' &&
|
|
992
|
+
context.refCellWrappedBindingIds.has(expression.reference.binding.id)) {
|
|
993
|
+
const target = emitIdentifierReferenceRust(expression.reference, context);
|
|
994
|
+
if (expression.presence === 'narrowedPresent' &&
|
|
995
|
+
context.nullableBindingIds.has(expression.reference.binding.id))
|
|
996
|
+
return `${target}.borrow().clone().unwrap()`;
|
|
997
|
+
return `${target}.borrow().clone()`;
|
|
998
|
+
}
|
|
999
|
+
const dualSentinelUnion = getIrExpressionDualSentinelUnionRust(expression, context);
|
|
1000
|
+
if (expression.presence === 'narrowedPresent' && dualSentinelUnion) {
|
|
1001
|
+
const payloads = dualSentinelUnion.variants.filter((variant) => variant.kind === 'tuple');
|
|
1002
|
+
if (payloads.length !== 1) {
|
|
1003
|
+
emissionError(context, 'present dual-sentinel union requires one Rust payload alternative');
|
|
1004
|
+
}
|
|
1005
|
+
const target = emitIdentifierReferenceRust(expression.reference, context);
|
|
1006
|
+
return `match &${target} { ${dualSentinelUnion.name}::${payloads[0].name}(value) => value.clone(), _ => unreachable!() }`;
|
|
1007
|
+
}
|
|
1008
|
+
if (expression.presence === 'narrowedPresent' &&
|
|
1009
|
+
expression.reference.kind === 'binding' &&
|
|
1010
|
+
context.nullableBindingIds.has(expression.reference.binding.id))
|
|
1011
|
+
return `${emitIdentifierReferenceRust(expression.reference, context)}.clone().unwrap()`;
|
|
1012
|
+
const narrowedReceiver = emitPrimitiveUnionNarrowedReceiverRust(expression, context);
|
|
1013
|
+
if (narrowedReceiver)
|
|
1014
|
+
return expression.narrowedMember === 'string' ? `${narrowedReceiver}.clone()` : `*${narrowedReceiver}`;
|
|
1015
|
+
return emitIdentifierReferenceRust(expression.reference, context);
|
|
1016
|
+
}
|
|
1017
|
+
case 'literal':
|
|
1018
|
+
return emitLiteral(expression.value);
|
|
1019
|
+
case 'new':
|
|
1020
|
+
if (expression.callee.kind !== 'identifier') {
|
|
1021
|
+
emissionError(context, 'qualified constructors require Rust type-path lowering');
|
|
1022
|
+
}
|
|
1023
|
+
assertIrConstructorInvocationAbiRust(expression, context);
|
|
1024
|
+
{
|
|
1025
|
+
const constructor = emitConstructorReferenceRust(expression.callee.reference, context);
|
|
1026
|
+
if (expression.callee.reference.kind === 'ambient' &&
|
|
1027
|
+
rustTypedArrayConstructorNames.has(expression.callee.reference.name)) {
|
|
1028
|
+
const oneArgument = expression.arguments[0];
|
|
1029
|
+
const method = expression.arguments.length === 1 && oneArgument && isIrExpressionArrayBufferRust(oneArgument, context)
|
|
1030
|
+
? 'from_buffer'
|
|
1031
|
+
: ['empty', 'from_source', 'from_buffer_offset', 'from_buffer_range'][expression.arguments.length];
|
|
1032
|
+
if (!method)
|
|
1033
|
+
emissionError(context, 'typed-array construction supports zero through three arguments');
|
|
1034
|
+
return `${constructor}::${method}(${expression.arguments.map((argument) => emitOwnedOperandRust(argument, context)).join(', ')})`;
|
|
1035
|
+
}
|
|
1036
|
+
if (expression.callee.reference.kind === 'ambient' && expression.callee.reference.name === 'DataView') {
|
|
1037
|
+
const method = [undefined, 'from_buffer', 'from_buffer_offset', 'from_buffer_range'][expression.arguments.length];
|
|
1038
|
+
if (!method)
|
|
1039
|
+
emissionError(context, 'DataView construction supports one through three arguments');
|
|
1040
|
+
return `${constructor}::${method}(${expression.arguments.map((argument) => emitOwnedOperandRust(argument, context)).join(', ')})`;
|
|
1041
|
+
}
|
|
1042
|
+
return `${constructor}::new(${expression.arguments.map((argument) => emitOwnedOperandRust(argument, context)).join(', ')})`;
|
|
1043
|
+
}
|
|
1044
|
+
case 'object':
|
|
1045
|
+
return emitObjectExpressionRust(expression, context);
|
|
1046
|
+
case 'objectRest':
|
|
1047
|
+
return emitObjectRestExpressionRust(expression, context);
|
|
1048
|
+
case 'property': {
|
|
1049
|
+
if (expression.optional)
|
|
1050
|
+
return emitOptionalPropertyExpressionRust(expression, context);
|
|
1051
|
+
const namespaceMember = expression.namespaceMember;
|
|
1052
|
+
if (namespaceMember?.kind === 'binding') {
|
|
1053
|
+
const owner = context.numericEnumNamespaceNames.get(namespaceMember.binding.id);
|
|
1054
|
+
const namespaceFunction = context.module.declarations.some((declaration) => declaration.kind === 'function' &&
|
|
1055
|
+
declaration.binding.name === expression.name &&
|
|
1056
|
+
declaration.namespaceMember?.kind === 'binding' &&
|
|
1057
|
+
declaration.namespaceMember.binding.id === namespaceMember.binding.id);
|
|
1058
|
+
if (owner && namespaceFunction)
|
|
1059
|
+
return `${owner}::${safeRustValueName(expression.name)}`;
|
|
1060
|
+
}
|
|
1061
|
+
// Rust spells a collection's length `len()`, and it counts in `usize` while the neutral numeric
|
|
1062
|
+
// domain is one type. The cast is what keeps the comparison it feeds well typed.
|
|
1063
|
+
// A member of the ambient surface is spelled by the table, not by the source's name. Rust
|
|
1064
|
+
// counts in `usize`, so a counting member is cast back into the neutral numeric domain.
|
|
1065
|
+
if (expression.member) {
|
|
1066
|
+
const binding = getCompilerRustAmbientMemberBinding(expression.member);
|
|
1067
|
+
if (!binding) {
|
|
1068
|
+
emissionError(context, `${expression.member.receiver} member ${expression.member.name} has no Rust binding`);
|
|
1069
|
+
}
|
|
1070
|
+
if (binding.kind === 'countingMethod') {
|
|
1071
|
+
const countingReceiver = emitPrimitiveUnionNarrowedReceiverRust(expression.object, context) ??
|
|
1072
|
+
emitExpression(expression.object, context);
|
|
1073
|
+
return `(${countingReceiver}.${binding.targetName}() as f64)`;
|
|
1074
|
+
}
|
|
1075
|
+
if (binding.kind === 'propertyMethod') {
|
|
1076
|
+
return `${emitExpression(expression.object, context)}.${binding.targetName}()`;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
// A union is a closed set of alternatives in Rust, so its fields are not reachable by name.
|
|
1080
|
+
// A reference control flow narrowed to one alternative reads that alternative's own field; an
|
|
1081
|
+
// unnarrowed one can only read what every alternative agrees on, through the shared accessor.
|
|
1082
|
+
// A class's static members belong to the type, not to a value of it, so Rust paths into the
|
|
1083
|
+
// type: an associated constant for a field and an associated function for a method. Reading
|
|
1084
|
+
// either off a value is the source language's spelling, not Rust's.
|
|
1085
|
+
const classDeclaration = getIrExpressionClassDeclarationRust(expression.object, context);
|
|
1086
|
+
if (classDeclaration) {
|
|
1087
|
+
const field = classDeclaration.fields.find((candidate) => candidate.static && candidate.name === expression.name);
|
|
1088
|
+
const method = classDeclaration.methods.find((candidate) => candidate.static && candidate.name === expression.name);
|
|
1089
|
+
if (field || method) {
|
|
1090
|
+
return `${getBindingTargetNameRust(classDeclaration.binding, context)}::${field ? constantRustName(expression.name) : safeRustValueName(expression.name)}`;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
// An enum member is a variant, not a field: Rust paths into the type rather than reading off a
|
|
1094
|
+
// value, and the variant keeps the source's own spelling.
|
|
1095
|
+
const enumeration = getIrExpressionEnumDeclarationRust(expression.object, context);
|
|
1096
|
+
if (enumeration) {
|
|
1097
|
+
return `${getBindingTargetNameRust(enumeration.binding, context)}::${safeRustTypeName(expression.name)}`;
|
|
1098
|
+
}
|
|
1099
|
+
// Reading a member of a narrowed `Option` only needs to look at it, so it is borrowed open
|
|
1100
|
+
// rather than copied out.
|
|
1101
|
+
const borrowedNarrow = emitBorrowedNarrowedReceiverRust(expression.object, context);
|
|
1102
|
+
if (borrowedNarrow !== undefined) {
|
|
1103
|
+
return `${borrowedNarrow}.${safeRustValueName(expression.name)}`;
|
|
1104
|
+
}
|
|
1105
|
+
const accessor = getIrExpressionClassAccessorRust(expression.object, expression.name, 'get', context);
|
|
1106
|
+
if (accessor)
|
|
1107
|
+
return `${emitExpression(expression.object, context)}.${safeRustValueName(expression.name)}()`;
|
|
1108
|
+
const union = getIrExpressionTaggedUnionRust(expression.object, context);
|
|
1109
|
+
if (union) {
|
|
1110
|
+
const object = emitExpression(expression.object, context);
|
|
1111
|
+
return expression.object.kind === 'identifier' && expression.object.narrowedMember
|
|
1112
|
+
? `${object}.as_${safeRustValueName(expression.object.narrowedMember)}().${safeRustValueName(expression.name)}`
|
|
1113
|
+
: `${object}.${safeRustValueName(expression.name)}()`;
|
|
1114
|
+
}
|
|
1115
|
+
// A namespace-like ambient symbol has no target name of its own, so the member decides the
|
|
1116
|
+
// whole spelling: `Math.max` is `f64::max`, not `Math::max`.
|
|
1117
|
+
if (expression.object.kind === 'identifier' && expression.object.reference.kind === 'ambient') {
|
|
1118
|
+
const member = getCompilerRuntimeExternalMemberTargetRust(expression.object.reference.name, expression.name, context.options.hostBindings);
|
|
1119
|
+
if (member)
|
|
1120
|
+
return member;
|
|
1121
|
+
}
|
|
1122
|
+
if (expression.object.kind === 'identifier' &&
|
|
1123
|
+
expression.object.reference.kind === 'this' &&
|
|
1124
|
+
context.abstractFieldNames.has(expression.name)) {
|
|
1125
|
+
return `self.${safeRustValueName(expression.name)}()`;
|
|
1126
|
+
}
|
|
1127
|
+
if (expression.object.kind === 'identifier' &&
|
|
1128
|
+
expression.object.reference.kind === 'this' &&
|
|
1129
|
+
context.compositionBase &&
|
|
1130
|
+
isIrCompositionBaseMemberRust(expression.name, context.compositionBase.baseDeclaration)) {
|
|
1131
|
+
const baseField = context.compositionBase.baseDeclaration.fields.find((candidate) => !candidate.static && candidate.name === expression.name);
|
|
1132
|
+
const cloneSuffix = baseField && !isIrTypeCopyValueRust(baseField.type) ? '.clone()' : '';
|
|
1133
|
+
return `self.${safeRustValueName(context.compositionBase.fieldName)}.${safeRustValueName(expression.name)}${cloneSuffix}`;
|
|
1134
|
+
}
|
|
1135
|
+
const needsClone = expression.object.kind === 'element' ||
|
|
1136
|
+
(expression.object.kind === 'identifier' &&
|
|
1137
|
+
expression.object.reference.kind === 'this' &&
|
|
1138
|
+
isIrSelfFieldNonCopyRust(expression.name, context));
|
|
1139
|
+
const owned = needsClone ? '.clone()' : '';
|
|
1140
|
+
return `${emitExpression(expression.object, context)}${isAmbientIdentifier(expression.object) ? '::' : '.'}${safeRustValueName(expression.name)}${owned}`;
|
|
1141
|
+
}
|
|
1142
|
+
case 'regexp':
|
|
1143
|
+
emissionError(context, 'regular expressions require a downstream standard-library mapping');
|
|
1144
|
+
case 'spread':
|
|
1145
|
+
// As in Haxe: a fixed tuple spread is already normalized away, so what reaches here spreads an
|
|
1146
|
+
// unbounded collection into a fixed-arity callee, and Rust has no variadic call to lower it to.
|
|
1147
|
+
emissionError(context, 'spreading an unbounded collection requires a fold or a variadic target');
|
|
1148
|
+
case 'template': {
|
|
1149
|
+
const format = expression.parts
|
|
1150
|
+
.map((part) => (typeof part === 'string' ? part.replaceAll('{', '{{').replaceAll('}', '}}') : '{}'))
|
|
1151
|
+
.join('');
|
|
1152
|
+
const values = expression.parts.flatMap((part) => typeof part === 'string' ? [] : [emitExpression(part, context)]);
|
|
1153
|
+
return `format!(${JSON.stringify(format)}${values.length > 0 ? `, ${values.join(', ')}` : ''})`;
|
|
1154
|
+
}
|
|
1155
|
+
case 'tuple': {
|
|
1156
|
+
const elements = expression.elements.map((element) => {
|
|
1157
|
+
if (!element.expression)
|
|
1158
|
+
return 'None';
|
|
1159
|
+
const emitted = emitExpression(element.expression, context);
|
|
1160
|
+
return element.optional ? `Some(${emitted})` : emitted;
|
|
1161
|
+
});
|
|
1162
|
+
return `(${elements.join(', ')}${elements.length === 1 ? ',' : ''})`;
|
|
1163
|
+
}
|
|
1164
|
+
case 'tupleSpread':
|
|
1165
|
+
return emitTupleSpreadExpressionRust(expression, context);
|
|
1166
|
+
case 'tupleRest':
|
|
1167
|
+
return `${emitExpression(expression.object, context)}.${String(expression.start)}`;
|
|
1168
|
+
case 'tupleSuffix': {
|
|
1169
|
+
const object = emitExpression(expression.object, context);
|
|
1170
|
+
const elements = Array.from({ length: expression.width }, (_, offset) => `${object}.${String(expression.start + offset)}`);
|
|
1171
|
+
return `(${elements.join(', ')}${elements.length === 1 ? ',' : ''})`;
|
|
1172
|
+
}
|
|
1173
|
+
case 'unary': {
|
|
1174
|
+
if (expression.operator === '++' || expression.operator === '--') {
|
|
1175
|
+
return emitNumericUpdateUnaryRust(expression, context);
|
|
1176
|
+
}
|
|
1177
|
+
if (expression.operator === 'void') {
|
|
1178
|
+
return `{ ${emitExpression(expression.operand, context)}; () }`;
|
|
1179
|
+
}
|
|
1180
|
+
if (expression.operator === 'typeof') {
|
|
1181
|
+
const sourceName = getStaticTypeofNameRust(expression.semantics.operand.flow);
|
|
1182
|
+
if (!sourceName) {
|
|
1183
|
+
emissionError(context, `typeof on ${expression.semantics.operand.flow} requires Rust runtime representation evidence`);
|
|
1184
|
+
}
|
|
1185
|
+
if (expression.semantics.operand.flow === 'undefined')
|
|
1186
|
+
return '"undefined".to_owned()';
|
|
1187
|
+
return `{ let _ = &${emitExpression(expression.operand, context)}; ${JSON.stringify(sourceName)}.to_owned() }`;
|
|
1188
|
+
}
|
|
1189
|
+
const operand = expression.semantics.operand.flow === 'number'
|
|
1190
|
+
? emitNumericEnumOperandRust(expression.operand, context)
|
|
1191
|
+
: emitExpression(expression.operand, context);
|
|
1192
|
+
const operator = emitPrefixUnaryOperatorRust(expression.operator, expression.semantics, context);
|
|
1193
|
+
if (expression.operator === '~')
|
|
1194
|
+
return `(!(${operand} as i32) as f64)`;
|
|
1195
|
+
if (expression.operator === '+' && expression.semantics.operand.flow === 'number')
|
|
1196
|
+
return operand;
|
|
1197
|
+
return `${operator}${operand}`;
|
|
1198
|
+
}
|
|
1199
|
+
case 'undefinedValue':
|
|
1200
|
+
getIrTypeOptionalPayloadRust(expression.type, 'contextual undefined value', context);
|
|
1201
|
+
return 'None';
|
|
1202
|
+
case 'undefinedDefault':
|
|
1203
|
+
return `${emitExpression(expression.value, context)}.unwrap_or_else(|| ${emitExpression(expression.fallback, context)})`;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
function emitTypedArrayElementAssignmentRust(expression, context) {
|
|
1207
|
+
if (expression.left.kind !== 'element' || !hasOnlyIrTypedArrayReceiversRust(expression.left.semantics.receivers)) {
|
|
1208
|
+
return undefined;
|
|
1209
|
+
}
|
|
1210
|
+
assertOneIrTypedArrayReceiverRust(expression.left.semantics.receivers, context);
|
|
1211
|
+
if (expression.semantics.right.flow !== 'number' ||
|
|
1212
|
+
(expression.operator !== '=' && expression.semantics.left.flow !== 'number')) {
|
|
1213
|
+
emissionError(context, `operator ${expression.operator} on a typed-array element requires numeric Rust lowering`);
|
|
1214
|
+
}
|
|
1215
|
+
const receiverName = getGeneratedTargetNameRust('typed_array', context);
|
|
1216
|
+
const indexName = getGeneratedTargetNameRust('typed_index', context);
|
|
1217
|
+
const valueName = getGeneratedTargetNameRust('typed_value', context);
|
|
1218
|
+
const receiver = emitExpression(expression.left.object, context);
|
|
1219
|
+
const index = emitNumericEnumOperandRust(expression.left.index, context);
|
|
1220
|
+
if (expression.operator === '=') {
|
|
1221
|
+
const right = expression.semantics.right.flow === 'number'
|
|
1222
|
+
? emitNumericEnumOperandRust(expression.right, context)
|
|
1223
|
+
: emitExpression(expression.right, context);
|
|
1224
|
+
return `{ let ${receiverName} = &${receiver}; let ${indexName} = ${index}; let ${valueName} = ${right}; ${receiverName}.set_index(${indexName}, ${valueName}) }`;
|
|
1225
|
+
}
|
|
1226
|
+
const currentName = getGeneratedTargetNameRust('typed_current', context);
|
|
1227
|
+
const rightName = getGeneratedTargetNameRust('typed_right', context);
|
|
1228
|
+
const right = emitNumericEnumOperandRust(expression.right, context);
|
|
1229
|
+
if (expression.operator === '||=' || expression.operator === '&&=') {
|
|
1230
|
+
const assignCondition = expression.operator === '||='
|
|
1231
|
+
? `${currentName} == 0.0 || ${currentName}.is_nan()`
|
|
1232
|
+
: `${currentName} != 0.0 && !${currentName}.is_nan()`;
|
|
1233
|
+
return `{ let ${receiverName} = &${receiver}; let ${indexName} = ${index}; let ${currentName} = ${receiverName}.get_index(${indexName}); if ${assignCondition} { let ${valueName} = ${right}; ${receiverName}.set_index(${indexName}, ${valueName}) } else { ${currentName} } }`;
|
|
1234
|
+
}
|
|
1235
|
+
if (expression.operator === '??=') {
|
|
1236
|
+
emissionError(context, 'operator ??= on a typed-array element requires absent-index lowering');
|
|
1237
|
+
}
|
|
1238
|
+
let operation;
|
|
1239
|
+
if (expression.operator === '**=') {
|
|
1240
|
+
operation = `f64::powf(${currentName}, ${rightName})`;
|
|
1241
|
+
}
|
|
1242
|
+
else if (expression.operator === '>>>=') {
|
|
1243
|
+
operation = `(((((${currentName} as i32) as u32) >> (${rightName} as u32)) as f64))`;
|
|
1244
|
+
}
|
|
1245
|
+
else if (expression.operator === '&=' ||
|
|
1246
|
+
expression.operator === '|=' ||
|
|
1247
|
+
expression.operator === '^=' ||
|
|
1248
|
+
expression.operator === '<<=' ||
|
|
1249
|
+
expression.operator === '>>=') {
|
|
1250
|
+
operation = `(((${currentName} as i32) ${expression.operator.slice(0, -1)} (${rightName} as i32)) as f64)`;
|
|
1251
|
+
}
|
|
1252
|
+
else if (expression.operator === '+=' ||
|
|
1253
|
+
expression.operator === '-=' ||
|
|
1254
|
+
expression.operator === '*=' ||
|
|
1255
|
+
expression.operator === '/=' ||
|
|
1256
|
+
expression.operator === '%=') {
|
|
1257
|
+
operation = `${currentName} ${expression.operator.slice(0, -1)} ${rightName}`;
|
|
1258
|
+
}
|
|
1259
|
+
else {
|
|
1260
|
+
emissionError(context, `operator ${expression.operator} on a typed-array element requires Rust lowering`);
|
|
1261
|
+
}
|
|
1262
|
+
return `{ let ${receiverName} = &${receiver}; let ${indexName} = ${index}; let ${currentName} = ${receiverName}.get_index(${indexName}); let ${rightName} = ${right}; let ${valueName} = ${operation}; ${receiverName}.set_index(${indexName}, ${valueName}) }`;
|
|
1263
|
+
}
|
|
1264
|
+
function hasOnlyIrTypedArrayReceiversRust(receivers) {
|
|
1265
|
+
return receivers.every((receiver) => rustTypedArrayReceiverNames.has(receiver));
|
|
1266
|
+
}
|
|
1267
|
+
function assertOneIrTypedArrayReceiverRust(receivers, context) {
|
|
1268
|
+
if (receivers.length !== 1) {
|
|
1269
|
+
emissionError(context, 'mixed typed-array receivers require Rust representation-union lowering');
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
function isIrExpressionTypedArrayRust(expression, context) {
|
|
1273
|
+
let type;
|
|
1274
|
+
if (expression.kind === 'identifier' && expression.reference.kind === 'binding') {
|
|
1275
|
+
type = context.bindingTypes.get(expression.reference.binding.id);
|
|
1276
|
+
}
|
|
1277
|
+
else if (expression.kind === 'call') {
|
|
1278
|
+
if (expression.callee.kind === 'property' &&
|
|
1279
|
+
expression.callee.member?.receiver === 'typedArray' &&
|
|
1280
|
+
(expression.callee.member.name === 'slice' || expression.callee.member.name === 'subarray')) {
|
|
1281
|
+
return true;
|
|
1282
|
+
}
|
|
1283
|
+
type = expression.semantics.resultType;
|
|
1284
|
+
}
|
|
1285
|
+
else if (expression.kind === 'cast') {
|
|
1286
|
+
type = expression.type;
|
|
1287
|
+
}
|
|
1288
|
+
else if (expression.kind === 'new' &&
|
|
1289
|
+
expression.callee.kind === 'identifier' &&
|
|
1290
|
+
expression.callee.reference.kind === 'ambient') {
|
|
1291
|
+
return rustTypedArrayConstructorNames.has(expression.callee.reference.name);
|
|
1292
|
+
}
|
|
1293
|
+
return isIrTypeTypedArrayRust(type);
|
|
1294
|
+
}
|
|
1295
|
+
function isIrExpressionArrayBufferRust(expression, context) {
|
|
1296
|
+
if (expression.kind === 'identifier' && expression.reference.kind === 'binding') {
|
|
1297
|
+
const type = context.bindingTypes.get(expression.reference.binding.id);
|
|
1298
|
+
return type?.kind === 'named' && type.reference.kind === 'ambient' && type.reference.name === 'ArrayBuffer';
|
|
1299
|
+
}
|
|
1300
|
+
if (expression.kind === 'property' &&
|
|
1301
|
+
expression.name === 'buffer' &&
|
|
1302
|
+
(expression.member?.receiver === 'dataView' || expression.member?.receiver === 'typedArray')) {
|
|
1303
|
+
return true;
|
|
1304
|
+
}
|
|
1305
|
+
if (expression.kind === 'cast') {
|
|
1306
|
+
return (expression.type.kind === 'named' &&
|
|
1307
|
+
expression.type.reference.kind === 'ambient' &&
|
|
1308
|
+
expression.type.reference.name === 'ArrayBuffer');
|
|
1309
|
+
}
|
|
1310
|
+
return (expression.kind === 'new' &&
|
|
1311
|
+
expression.callee.kind === 'identifier' &&
|
|
1312
|
+
expression.callee.reference.kind === 'ambient' &&
|
|
1313
|
+
expression.callee.reference.name === 'ArrayBuffer');
|
|
1314
|
+
}
|
|
1315
|
+
function isIrExpressionDataViewRust(expression, context) {
|
|
1316
|
+
let type;
|
|
1317
|
+
if (expression.kind === 'identifier' && expression.reference.kind === 'binding') {
|
|
1318
|
+
type = context.bindingTypes.get(expression.reference.binding.id);
|
|
1319
|
+
}
|
|
1320
|
+
else if (expression.kind === 'cast') {
|
|
1321
|
+
type = expression.type;
|
|
1322
|
+
}
|
|
1323
|
+
else if (expression.kind === 'new' &&
|
|
1324
|
+
expression.callee.kind === 'identifier' &&
|
|
1325
|
+
expression.callee.reference.kind === 'ambient') {
|
|
1326
|
+
return expression.callee.reference.name === 'DataView';
|
|
1327
|
+
}
|
|
1328
|
+
return type?.kind === 'named' && type.reference.kind === 'ambient' && type.reference.name === 'DataView';
|
|
1329
|
+
}
|
|
1330
|
+
function isIrTypeTypedArrayRust(type) {
|
|
1331
|
+
return (type?.kind === 'named' &&
|
|
1332
|
+
type.reference.kind === 'ambient' &&
|
|
1333
|
+
rustTypedArrayConstructorNames.has(type.reference.name));
|
|
1334
|
+
}
|
|
1335
|
+
// `Promise<T>` in the return position of an `async fn` is the future Rust already builds, so the
|
|
1336
|
+
// emitted signature carries `T`. Anywhere else the task type has no native spelling yet.
|
|
1337
|
+
function getIrTaskAwaitedTypeRust(type, context) {
|
|
1338
|
+
if (type.kind !== 'named' || type.reference.kind !== 'ambient' || type.reference.name !== 'Promise') {
|
|
1339
|
+
emissionError(context, 'an async function must return a task type');
|
|
1340
|
+
}
|
|
1341
|
+
const awaited = type.typeArguments[0];
|
|
1342
|
+
if (type.typeArguments.length !== 1 || !awaited) {
|
|
1343
|
+
emissionError(context, 'a task type requires one awaited type argument');
|
|
1344
|
+
}
|
|
1345
|
+
return awaited;
|
|
1346
|
+
}
|
|
1347
|
+
// Rust distinguishes a method that observes its receiver from one that changes it, and the two are
|
|
1348
|
+
// not interchangeable to a caller. Taking `&mut self` everywhere is the conservative choice that
|
|
1349
|
+
// makes every method exclusive, so a shared read of one value blocks a read of another. The mutation
|
|
1350
|
+
// evidence is already in the body: an assignment whose target reaches `this`, or a bare rebinding of
|
|
1351
|
+
// it, is what requires exclusivity.
|
|
1352
|
+
// Which methods need an exclusive receiver. Writing through `this` is the direct case; calling a
|
|
1353
|
+
// method that writes is the transitive one, and missing it emits a `&self` method that calls a
|
|
1354
|
+
// `&mut self` method — which Rust rejects. The relation is closed to a fixed point because a caller
|
|
1355
|
+
// of a caller needs the same receiver.
|
|
1356
|
+
// Keyed by the name the method is emitted under, not the name it was written under: a getter and a
|
|
1357
|
+
// setter share one source name and Rust gives them two, so keying by the source name would hand the
|
|
1358
|
+
// getter the setter's mutable receiver.
|
|
1359
|
+
function getIrClassMutatingMethodNamesRust(declaration) {
|
|
1360
|
+
const mutating = new Set(declaration.methods
|
|
1361
|
+
.filter((method) => hasIrFunctionSignatureThisMutationRust(method))
|
|
1362
|
+
.map((method) => getIrClassMethodTargetNameRust(method)));
|
|
1363
|
+
const calls = new Map(declaration.methods.map((method) => [getIrClassMethodTargetNameRust(method), getIrFunctionSignatureSelfCallNamesRust(method)]));
|
|
1364
|
+
let changed = true;
|
|
1365
|
+
while (changed) {
|
|
1366
|
+
changed = false;
|
|
1367
|
+
for (const method of declaration.methods) {
|
|
1368
|
+
const target = getIrClassMethodTargetNameRust(method);
|
|
1369
|
+
if (mutating.has(target))
|
|
1370
|
+
continue;
|
|
1371
|
+
if ((calls.get(target) ?? []).some((name) => mutating.has(safeRustValueName(name)))) {
|
|
1372
|
+
mutating.add(target);
|
|
1373
|
+
changed = true;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return mutating;
|
|
1378
|
+
}
|
|
1379
|
+
function getIrFunctionSignatureSelfCallNamesRust(method) {
|
|
1380
|
+
const names = [];
|
|
1381
|
+
const observer = {
|
|
1382
|
+
expression(expression) {
|
|
1383
|
+
if (expression.kind === 'call' &&
|
|
1384
|
+
expression.callee.kind === 'property' &&
|
|
1385
|
+
expression.callee.object.kind === 'identifier' &&
|
|
1386
|
+
expression.callee.object.reference.kind === 'this') {
|
|
1387
|
+
names.push(expression.callee.name);
|
|
1388
|
+
}
|
|
1389
|
+
return undefined;
|
|
1390
|
+
},
|
|
1391
|
+
};
|
|
1392
|
+
method.body.forEach((statement) => analyzeIrStatementSubtreeTraversal(statement, observer));
|
|
1393
|
+
return names;
|
|
1394
|
+
}
|
|
1395
|
+
function hasIrFunctionSignatureThisMutationRust(method) {
|
|
1396
|
+
let mutates = false;
|
|
1397
|
+
const reachesThis = (expression) => {
|
|
1398
|
+
if (expression.kind === 'identifier')
|
|
1399
|
+
return expression.reference.kind === 'this';
|
|
1400
|
+
if (expression.kind === 'property' || expression.kind === 'element')
|
|
1401
|
+
return reachesThis(expression.object);
|
|
1402
|
+
return false;
|
|
1403
|
+
};
|
|
1404
|
+
const observer = {
|
|
1405
|
+
expression(expression) {
|
|
1406
|
+
// An assignment and an update both write through their target. `this.count++` is a mutation
|
|
1407
|
+
// as much as `this.count = 1`, and the untyped walk this replaced missed it entirely.
|
|
1408
|
+
const target = expression.kind === 'assignment'
|
|
1409
|
+
? expression.left
|
|
1410
|
+
: expression.kind === 'unary'
|
|
1411
|
+
? expression.operand
|
|
1412
|
+
: undefined;
|
|
1413
|
+
if (!target || !reachesThis(target))
|
|
1414
|
+
return undefined;
|
|
1415
|
+
mutates = true;
|
|
1416
|
+
return false;
|
|
1417
|
+
},
|
|
1418
|
+
};
|
|
1419
|
+
method.body.forEach((statement) => analyzeIrStatementSubtreeTraversal(statement, observer));
|
|
1420
|
+
return mutates;
|
|
1421
|
+
}
|
|
1422
|
+
function emitFunction(declaration, outer) {
|
|
1423
|
+
if (declaration.namespaceMember) {
|
|
1424
|
+
emissionError(outer, `value namespace function ${declaration.binding.name} requires Rust namespace lowering`);
|
|
1425
|
+
}
|
|
1426
|
+
const context = {
|
|
1427
|
+
...outer,
|
|
1428
|
+
activeTypeParameters: declaration.typeParameters,
|
|
1429
|
+
enclosingReturnType: declaration.returns,
|
|
1430
|
+
returnsAbsent: hasIrTypeAbsentMember(declaration.returns),
|
|
1431
|
+
};
|
|
1432
|
+
// Rust has native suspension, so it declines the neutral state-machine lowering that Haxe elects
|
|
1433
|
+
// and emits `async fn` instead. The awaited type of an async function is its return type: the
|
|
1434
|
+
// future is implied by `async`, so the task wrapper is dropped rather than named.
|
|
1435
|
+
return [
|
|
1436
|
+
`${declaration.exported ? 'pub ' : ''}${declaration.async ? 'async ' : ''}fn ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeParameters(declaration.typeParameters, context)}(${declaration.parameters.map((parameter) => emitParameter(parameter, context)).join(', ')}) -> ${emitType(declaration.async ? getIrTaskAwaitedTypeRust(declaration.returns, context) : declaration.returns, context)} {`,
|
|
1437
|
+
...indentSourceLines([
|
|
1438
|
+
...declaration.parameters.flatMap((parameter) => parameter.initializer
|
|
1439
|
+
? [
|
|
1440
|
+
`let ${getBindingTargetNameRust(parameter.binding, context)} = ${getBindingTargetNameRust(parameter.binding, context)}.unwrap_or_else(|| ${emitExpression(parameter.initializer, context)});`,
|
|
1441
|
+
]
|
|
1442
|
+
: []),
|
|
1443
|
+
...emitStatements(declaration.body, context),
|
|
1444
|
+
]),
|
|
1445
|
+
'}',
|
|
1446
|
+
];
|
|
1447
|
+
}
|
|
1448
|
+
function emitImports(imports, context) {
|
|
1449
|
+
const lines = new Set();
|
|
1450
|
+
for (const imported of imports) {
|
|
1451
|
+
if (imported.bindings.length === 0)
|
|
1452
|
+
continue;
|
|
1453
|
+
const module = rustImportModule(imported.specifier, context);
|
|
1454
|
+
const names = imported.bindings.map((binding) => {
|
|
1455
|
+
if (binding.imported === '*' || binding.imported === 'default') {
|
|
1456
|
+
emissionError(context, `${binding.imported} imports require explicit Rust mapping for ${imported.specifier}`);
|
|
1457
|
+
}
|
|
1458
|
+
const importedName = binding.binding.space === 'type' || /^[A-Z]/u.test(binding.imported)
|
|
1459
|
+
? safeRustTypeName(binding.imported)
|
|
1460
|
+
: safeRustValueName(binding.imported);
|
|
1461
|
+
const localName = getBindingTargetNameRust(binding.binding, context);
|
|
1462
|
+
return importedName === localName ? importedName : `${importedName} as ${localName}`;
|
|
1463
|
+
});
|
|
1464
|
+
lines.add(`use ${module}::${emitUseTreeRust(names.sort())};`);
|
|
1465
|
+
}
|
|
1466
|
+
return [...lines].sort();
|
|
1467
|
+
}
|
|
1468
|
+
// A facade module names what it re-exports and where it came from, which is exactly what Rust's
|
|
1469
|
+
// `pub use` says. The name a target spells it by depends on which space it lives in, so a re-export
|
|
1470
|
+
// carries the same value-versus-type decision an import does.
|
|
1471
|
+
function emitReexportsRust(exports, context) {
|
|
1472
|
+
const lines = new Set();
|
|
1473
|
+
for (const exported of exports) {
|
|
1474
|
+
if (exported.kind === 'local')
|
|
1475
|
+
continue;
|
|
1476
|
+
if (exported.kind === 'all') {
|
|
1477
|
+
lines.add(`pub use ${rustImportModule(exported.specifier, context)}::*;`);
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
if (exported.kind === 'namespace') {
|
|
1481
|
+
const target = safeRustValueName(exported.exported);
|
|
1482
|
+
lines.add(`pub use ${rustImportModule(exported.specifier, context)} as ${target};`);
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
if (exported.kind !== 'reexport')
|
|
1486
|
+
emissionError(context, 'default exports require Rust module-facade lowering');
|
|
1487
|
+
const module = rustImportModule(exported.specifier, context);
|
|
1488
|
+
const source = exported.typeOnly || /^[A-Z]/u.test(exported.imported)
|
|
1489
|
+
? safeRustTypeName(exported.imported)
|
|
1490
|
+
: safeRustValueName(exported.imported);
|
|
1491
|
+
const target = exported.typeOnly || /^[A-Z]/u.test(exported.exported)
|
|
1492
|
+
? safeRustTypeName(exported.exported)
|
|
1493
|
+
: safeRustValueName(exported.exported);
|
|
1494
|
+
lines.add(`pub use ${module}::${emitUseTreeRust([source === target ? source : `${source} as ${target}`])};`);
|
|
1495
|
+
}
|
|
1496
|
+
return [...lines].sort();
|
|
1497
|
+
}
|
|
1498
|
+
function emitInterface(declaration, context) {
|
|
1499
|
+
if (declaration.extends.length > 0)
|
|
1500
|
+
emissionError(context, `interface ${declaration.binding.name} inheritance requires record flattening`);
|
|
1501
|
+
// A shape a class implements is a contract on behaviour, which Rust spells as a trait. A shape
|
|
1502
|
+
// nothing implements is data, which Rust spells as a struct — and emitting the second as the first
|
|
1503
|
+
// would make an ordinary object type unconstructible.
|
|
1504
|
+
if (hasIrModuleClassImplementingRust(declaration, context)) {
|
|
1505
|
+
return emitTraitRust(declaration, context);
|
|
1506
|
+
}
|
|
1507
|
+
return emitRecord(getBindingTargetNameRust(declaration.binding, context), declaration.properties, declaration.typeParameters, declaration.exported, context);
|
|
1508
|
+
}
|
|
1509
|
+
function emitTraitRust(declaration, context) {
|
|
1510
|
+
const visibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
1511
|
+
return [
|
|
1512
|
+
`${visibility}trait ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeParameters(declaration.typeParameters, context)} {`,
|
|
1513
|
+
...declaration.properties.map((property) => {
|
|
1514
|
+
// A Rust trait holds no data, so a data property becomes the accessor that reads it. Fields and
|
|
1515
|
+
// methods live in different namespaces, so the accessor keeps the property's own name.
|
|
1516
|
+
if (property.type.kind !== 'function') {
|
|
1517
|
+
if (property.optional) {
|
|
1518
|
+
return emissionError(context, `interface ${declaration.binding.name} property ${property.name} requires Rust optional accessor lowering`);
|
|
1519
|
+
}
|
|
1520
|
+
return ` fn ${safeRustValueName(property.name)}(&self) -> ${emitType(property.type, context)};`;
|
|
1521
|
+
}
|
|
1522
|
+
const parameters = property.type.parameters
|
|
1523
|
+
.map((parameter, index) => `${safeRustValueName(parameter.name ?? `argument${String(index)}`)}: ${emitType(parameter.type, context)}`)
|
|
1524
|
+
.join(', ');
|
|
1525
|
+
return ` fn ${safeRustValueName(property.name)}(&self${parameters ? `, ${parameters}` : ''}) -> ${emitType(property.type.returns, context)};`;
|
|
1526
|
+
}),
|
|
1527
|
+
'}',
|
|
1528
|
+
];
|
|
1529
|
+
}
|
|
1530
|
+
function hasIrModuleClassImplementingRust(declaration, context) {
|
|
1531
|
+
return context.module.declarations.some((candidate) => candidate.kind === 'class' &&
|
|
1532
|
+
candidate.implements.some((implemented) => implemented.kind === 'named' &&
|
|
1533
|
+
implemented.reference.kind === 'binding' &&
|
|
1534
|
+
implemented.reference.binding.id === declaration.binding.id));
|
|
1535
|
+
}
|
|
1536
|
+
function emitConstructorReferenceRust(reference, context) {
|
|
1537
|
+
if (reference.kind === 'super')
|
|
1538
|
+
emissionError(context, 'super cannot be used as a Rust constructor value');
|
|
1539
|
+
if (reference.kind === 'this')
|
|
1540
|
+
emissionError(context, 'this cannot be used as a Rust constructor');
|
|
1541
|
+
if (reference.kind !== 'ambient')
|
|
1542
|
+
return getBindingTargetNameRust(reference.binding, context);
|
|
1543
|
+
const targetName = getCompilerRuntimeExternalSymbolTargetRust(reference.name, 'value', context.options.hostBindings);
|
|
1544
|
+
if (!targetName)
|
|
1545
|
+
emissionError(context, `external constructor ${reference.name} has no Rust binding`);
|
|
1546
|
+
return isCompilerRuntimeExternalSymbolProvidedRust(reference.name, 'value', context.options.hostBindings)
|
|
1547
|
+
? recordRuntimeTypeRust(targetName, context)
|
|
1548
|
+
: targetName;
|
|
1549
|
+
}
|
|
1550
|
+
function assertIrConstructorInvocationAbiRust(expression, context) {
|
|
1551
|
+
if (expression.callee.kind === 'identifier' && expression.callee.reference.kind === 'ambient')
|
|
1552
|
+
return;
|
|
1553
|
+
// A class this module declares has an associated `new` whenever its constructor was lowered to one,
|
|
1554
|
+
// so the call is emitted; a class whose constructor was refused has nothing to call.
|
|
1555
|
+
if (expression.callee.kind === 'identifier' && expression.callee.reference.kind === 'binding') {
|
|
1556
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'class' &&
|
|
1557
|
+
expression.callee.kind === 'identifier' &&
|
|
1558
|
+
expression.callee.reference.kind === 'binding' &&
|
|
1559
|
+
candidate.binding.id === expression.callee.reference.binding.id);
|
|
1560
|
+
if (target?.kind === 'class') {
|
|
1561
|
+
const abstractBase = getIrClassStatelessAbstractBaseRust(target, context);
|
|
1562
|
+
if (getIrClassConstructorFieldAssignmentsRust(target, abstractBase !== undefined))
|
|
1563
|
+
return;
|
|
1564
|
+
const concreteBase = !abstractBase ? getIrClassConcreteBaseRust(target, context) : undefined;
|
|
1565
|
+
if (concreteBase && getIrClassCompositionConstructorRust(target, concreteBase))
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
emissionError(context, 'class constructor calls require Rust initialization lowering');
|
|
1570
|
+
}
|
|
1571
|
+
function emitIdentifierReferenceRust(reference, context) {
|
|
1572
|
+
if (reference.kind === 'super')
|
|
1573
|
+
emissionError(context, 'super requires Rust inheritance lowering');
|
|
1574
|
+
if (reference.kind === 'this')
|
|
1575
|
+
return 'self';
|
|
1576
|
+
if (reference.kind === 'ambient') {
|
|
1577
|
+
if (reference.name === 'undefined') {
|
|
1578
|
+
emissionError(context, 'undefined expressions require Rust Option-aware lowering');
|
|
1579
|
+
}
|
|
1580
|
+
const targetName = getCompilerRuntimeExternalSymbolTargetRust(reference.name, 'value', context.options.hostBindings);
|
|
1581
|
+
if (!targetName)
|
|
1582
|
+
emissionError(context, `external value ${reference.name} has no Rust binding`);
|
|
1583
|
+
return isCompilerRuntimeExternalSymbolProvidedRust(reference.name, 'value', context.options.hostBindings)
|
|
1584
|
+
? recordRuntimeTypeRust(targetName, context)
|
|
1585
|
+
: targetName;
|
|
1586
|
+
}
|
|
1587
|
+
return getBindingTargetNameRust(reference.binding, context);
|
|
1588
|
+
}
|
|
1589
|
+
function emitLiteral(value) {
|
|
1590
|
+
if (typeof value === 'string')
|
|
1591
|
+
return `${JSON.stringify(value)}.to_owned()`;
|
|
1592
|
+
if (value === null)
|
|
1593
|
+
return 'None';
|
|
1594
|
+
if (typeof value === 'number' && Number.isInteger(value) && !/[eE]/u.test(String(value))) {
|
|
1595
|
+
return `${String(value)}.0`;
|
|
1596
|
+
}
|
|
1597
|
+
return String(value);
|
|
1598
|
+
}
|
|
1599
|
+
function emitCallArgumentsRust(expression, context) {
|
|
1600
|
+
const signature = expression.semantics.signature;
|
|
1601
|
+
if (signature &&
|
|
1602
|
+
signature.restParameter === undefined &&
|
|
1603
|
+
typeof signature.providedArgumentCount === 'number' &&
|
|
1604
|
+
signature.providedArgumentCount > signature.parameterCount) {
|
|
1605
|
+
emissionError(context, 'extra JavaScript call arguments require target-neutral erasure lowering');
|
|
1606
|
+
}
|
|
1607
|
+
const borrowed = getIrCallBorrowedPositionsRust(expression, context);
|
|
1608
|
+
const defaults = expression.semantics.defaultParameters;
|
|
1609
|
+
const optionals = expression.semantics.optionalParameters;
|
|
1610
|
+
if (!defaults && !optionals) {
|
|
1611
|
+
return expression.arguments.map((argument, index) => borrowed.has(index) ? emitLentOperandRust(argument, context) : emitOwnedOperandRust(argument, context));
|
|
1612
|
+
}
|
|
1613
|
+
const plan = defaults ?? optionals;
|
|
1614
|
+
if (!plan)
|
|
1615
|
+
return expression.arguments.map((argument) => emitOwnedOperandRust(argument, context));
|
|
1616
|
+
if (plan.providedArgumentCount === 'dynamic') {
|
|
1617
|
+
emissionError(context, 'spread calls into optional or default parameters require Rust ABI expansion lowering');
|
|
1618
|
+
}
|
|
1619
|
+
if (expression.arguments.length > plan.parameterCount) {
|
|
1620
|
+
emissionError(context, 'extra JavaScript call arguments require Rust ABI erasure lowering');
|
|
1621
|
+
}
|
|
1622
|
+
const wrapped = new Set([...(defaults?.defaulted ?? []), ...(optionals?.optional ?? [])]);
|
|
1623
|
+
const defaultProvided = new Map(defaults?.provided.map((provided) => [provided.position, provided]) ?? []);
|
|
1624
|
+
const optionalProvided = new Map(optionals?.provided.map((provided) => [provided.position, provided]) ?? []);
|
|
1625
|
+
return Array.from({ length: plan.parameterCount }, (_, index) => {
|
|
1626
|
+
const argument = expression.arguments[index];
|
|
1627
|
+
if (!argument) {
|
|
1628
|
+
if (!wrapped.has(index)) {
|
|
1629
|
+
emissionError(context, `missing required call argument at position ${String(index)}`);
|
|
1630
|
+
}
|
|
1631
|
+
return 'None';
|
|
1632
|
+
}
|
|
1633
|
+
const providedEvidence = defaultProvided.get(index) ?? optionalProvided.get(index);
|
|
1634
|
+
if (providedEvidence?.value === 'undefined' || argument.kind === 'undefinedValue')
|
|
1635
|
+
return 'None';
|
|
1636
|
+
const emitted = emitExpression(argument, context);
|
|
1637
|
+
const optionalEvidence = optionalProvided.get(index);
|
|
1638
|
+
if (optionalEvidence && hasIrTypeNullMemberRust(optionalEvidence.parameterType)) {
|
|
1639
|
+
return isNullableType(optionalEvidence.argumentType) ? `Some(${emitted})` : `Some(Some(${emitted}))`;
|
|
1640
|
+
}
|
|
1641
|
+
if (optionalEvidence &&
|
|
1642
|
+
isNullableType(optionalEvidence.parameterType) &&
|
|
1643
|
+
isNullableType(optionalEvidence.argumentType)) {
|
|
1644
|
+
return emitted;
|
|
1645
|
+
}
|
|
1646
|
+
return wrapped.has(index) ? `Some(${emitted})` : emitted;
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
function emitOptionalCallExpressionRust(expression, context) {
|
|
1650
|
+
const semantics = expression.semantics.optionalChain;
|
|
1651
|
+
if (!semantics)
|
|
1652
|
+
emissionError(context, 'optional call lacks neutral optional-chain evidence');
|
|
1653
|
+
const arguments_ = emitCallArgumentsRust(expression, context).join(', ');
|
|
1654
|
+
const callee = emitExpression(expression.callee, context);
|
|
1655
|
+
if (semantics.receiverNullish === 'excluded')
|
|
1656
|
+
return `${callee}(${arguments_})`;
|
|
1657
|
+
getIrTypeOptionalPayloadRust(semantics.receiverType, 'optional call receiver', context);
|
|
1658
|
+
const operation = isNullableType(semantics.valueType) ? 'and_then' : 'map';
|
|
1659
|
+
return `${callee}.as_ref().${operation}(|optional_chain_value| optional_chain_value(${arguments_}))`;
|
|
1660
|
+
}
|
|
1661
|
+
function emitOptionalElementExpressionRust(expression, context) {
|
|
1662
|
+
const semantics = expression.semantics.optionalChain;
|
|
1663
|
+
if (!semantics)
|
|
1664
|
+
emissionError(context, 'optional element access lacks neutral optional-chain evidence');
|
|
1665
|
+
if (semantics.receiverNullish === 'excluded') {
|
|
1666
|
+
return emitRequiredElementExpressionRust(expression, context);
|
|
1667
|
+
}
|
|
1668
|
+
const receiver = getIrTypeOptionalPayloadRust(semantics.receiverType, 'optional element receiver', context);
|
|
1669
|
+
const object = emitExpression(expression.object, context);
|
|
1670
|
+
const value = 'optional_chain_value';
|
|
1671
|
+
if (receiver.kind === 'tuple') {
|
|
1672
|
+
const index = getElementAccessTupleIndexRust(expression, context);
|
|
1673
|
+
const operation = receiver.elements[index]?.optional ? 'and_then' : 'map';
|
|
1674
|
+
return `${object}.as_ref().${operation}(|${value}| ${value}.${String(index)}.clone())`;
|
|
1675
|
+
}
|
|
1676
|
+
if (receiver.kind === 'array') {
|
|
1677
|
+
return `${object}.as_ref().and_then(|${value}| ${value}.get(${emitExpression(expression.index, context)} as usize).cloned())`;
|
|
1678
|
+
}
|
|
1679
|
+
emissionError(context, 'optional element access requires array or fixed-tuple receiver evidence');
|
|
1680
|
+
}
|
|
1681
|
+
function emitOptionalPropertyExpressionRust(expression, context) {
|
|
1682
|
+
const semantics = expression.optionalChain;
|
|
1683
|
+
if (!semantics)
|
|
1684
|
+
emissionError(context, 'optional property access lacks neutral optional-chain evidence');
|
|
1685
|
+
const object = emitExpression(expression.object, context);
|
|
1686
|
+
const property = safeRustValueName(expression.name);
|
|
1687
|
+
if (semantics.receiverNullish === 'excluded') {
|
|
1688
|
+
// Indexing yields a place the caller does not own, so the field read out of it is a copy.
|
|
1689
|
+
const owned = expression.object.kind === 'element' ? '.clone()' : '';
|
|
1690
|
+
return `${object}${isAmbientIdentifier(expression.object) ? '::' : '.'}${property}${owned}`;
|
|
1691
|
+
}
|
|
1692
|
+
getIrTypeOptionalPayloadRust(semantics.receiverType, 'optional property receiver', context);
|
|
1693
|
+
const operation = isNullableType(semantics.valueType) ? 'and_then' : 'map';
|
|
1694
|
+
return `${object}.as_ref().${operation}(|optional_chain_value| optional_chain_value.${property}.clone())`;
|
|
1695
|
+
}
|
|
1696
|
+
function emitRequiredElementExpressionRust(expression, context) {
|
|
1697
|
+
const closedSelection = emitClosedKeyElementSelectionRust(expression, context);
|
|
1698
|
+
if (closedSelection)
|
|
1699
|
+
return closedSelection;
|
|
1700
|
+
if (expression.semantics.receivers.includes('object')) {
|
|
1701
|
+
emissionError(context, 'computed object access requires JavaScript property-key coercion lowering');
|
|
1702
|
+
}
|
|
1703
|
+
if (expression.semantics.receivers.includes('tuple')) {
|
|
1704
|
+
const index = getElementAccessTupleIndexRust(expression, context);
|
|
1705
|
+
return `${emitExpression(expression.object, context)}.${String(index)}`;
|
|
1706
|
+
}
|
|
1707
|
+
return `${emitExpression(expression.object, context)}[${emitExpression(expression.index, context)} as usize]`;
|
|
1708
|
+
}
|
|
1709
|
+
// A finite string-key domain identifies every field this access can reach. Rust records have no
|
|
1710
|
+
// string subscript, so select the represented field explicitly while evaluating the receiver and key
|
|
1711
|
+
// once, in source order. Borrowing the receiver keeps the selection from moving a source binding; the
|
|
1712
|
+
// selected field is cloned into the expression's owned result.
|
|
1713
|
+
function emitClosedKeyElementSelectionRust(expression, context) {
|
|
1714
|
+
const keys = expression.semantics.closedKeys;
|
|
1715
|
+
if (!keys)
|
|
1716
|
+
return undefined;
|
|
1717
|
+
let objectType = inferIrExpressionTypeRust(expression.object, context);
|
|
1718
|
+
if (objectType?.kind === 'union' &&
|
|
1719
|
+
'presence' in expression.object &&
|
|
1720
|
+
expression.object.presence === 'narrowedPresent') {
|
|
1721
|
+
const present = objectType.types.filter((member) => member.kind !== 'null' && member.kind !== 'undefined');
|
|
1722
|
+
if (present.length === 1)
|
|
1723
|
+
objectType = present[0];
|
|
1724
|
+
}
|
|
1725
|
+
const properties = objectType ? getIrObjectTypePropertiesRust(objectType, context) : undefined;
|
|
1726
|
+
if (!objectType || !properties) {
|
|
1727
|
+
emissionError(context, 'closed-key element access requires represented Rust object storage');
|
|
1728
|
+
}
|
|
1729
|
+
const members = new Map(properties
|
|
1730
|
+
.filter((property) => !property.computedKey && !property.phantom)
|
|
1731
|
+
.map((property) => [property.name, property]));
|
|
1732
|
+
const selections = keys.map((key) => ({ key, property: members.get(key) }));
|
|
1733
|
+
const absent = selections.find((selection) => !selection.property);
|
|
1734
|
+
if (absent) {
|
|
1735
|
+
emissionError(context, `closed key ${absent.key} is not a represented Rust object member`);
|
|
1736
|
+
}
|
|
1737
|
+
const memberTypes = selections.map(({ property }) => {
|
|
1738
|
+
const emitted = emitType(property.type, context);
|
|
1739
|
+
return property.optional ? `Option<${emitted}>` : emitted;
|
|
1740
|
+
});
|
|
1741
|
+
const distinctTypes = [...new Set(memberTypes)];
|
|
1742
|
+
if (distinctTypes.length !== 1) {
|
|
1743
|
+
emissionError(context, `closed-key selection over ${String(distinctTypes.length)} member types requires one Rust representation`);
|
|
1744
|
+
}
|
|
1745
|
+
const receiver = getGeneratedTargetNameRust('selection_receiver', context);
|
|
1746
|
+
const selectionKey = getGeneratedTargetNameRust('selection_key', context);
|
|
1747
|
+
const branches = selections.map(({ key, property }) => `${JSON.stringify(key)} => ${receiver}.${safeRustValueName(property.name)}.clone(),`);
|
|
1748
|
+
return `{ let ${receiver} = &${emitExpression(expression.object, context)}; let ${selectionKey} = &${emitExpression(expression.index, context)}; match ${selectionKey}.as_str() { ${branches.join(' ')} _ => unreachable!("Flight finite-key selection reached no member"), } }`;
|
|
1749
|
+
}
|
|
1750
|
+
function getIrTypeOptionalPayloadRust(type, subject, context) {
|
|
1751
|
+
if (type.kind !== 'union')
|
|
1752
|
+
emissionError(context, `${subject} requires one concrete Rust Option payload`);
|
|
1753
|
+
const concrete = type.types.filter((member) => member.kind !== 'null' && member.kind !== 'undefined');
|
|
1754
|
+
if (concrete.length !== 1)
|
|
1755
|
+
emissionError(context, `${subject} requires one concrete Rust Option payload`);
|
|
1756
|
+
return concrete[0];
|
|
1757
|
+
}
|
|
1758
|
+
function emitObjectRestExpressionRust(expression, context) {
|
|
1759
|
+
if (expression.excluded.some((key) => key.kind === 'computed')) {
|
|
1760
|
+
emissionError(context, 'computed object rest requires Rust property-key and record projection lowering');
|
|
1761
|
+
}
|
|
1762
|
+
const properties = getIrObjectRestPropertiesRust(expression, context);
|
|
1763
|
+
if (!properties)
|
|
1764
|
+
emissionError(context, 'object rest requires closed residual-record type evidence');
|
|
1765
|
+
const shape = createIrObjectTypeShapeIdentity(properties);
|
|
1766
|
+
const existing = context.objectRestRecords.get(shape);
|
|
1767
|
+
const recordName = existing?.name ?? getGeneratedTargetNameRust('ObjectRestRecord', context);
|
|
1768
|
+
if (!existing)
|
|
1769
|
+
context.objectRestRecords.set(shape, { name: recordName, properties });
|
|
1770
|
+
const object = emitExpression(expression.object, context);
|
|
1771
|
+
const fields = properties.map((property) => {
|
|
1772
|
+
const name = safeRustValueName(property.name);
|
|
1773
|
+
return {
|
|
1774
|
+
initializer: `${name}: ${object}.${name}.clone(),`,
|
|
1775
|
+
};
|
|
1776
|
+
});
|
|
1777
|
+
return `${recordName} { ${fields.map((field) => field.initializer).join(' ')} }`;
|
|
1778
|
+
}
|
|
1779
|
+
function getIrObjectRestPropertiesRust(expression, context) {
|
|
1780
|
+
const explicit = getIrObjectTypePropertiesRust(expression.type, context);
|
|
1781
|
+
if (explicit)
|
|
1782
|
+
return explicit;
|
|
1783
|
+
if (expression.object.reference.kind !== 'binding')
|
|
1784
|
+
return undefined;
|
|
1785
|
+
const sourceType = context.bindingTypes.get(expression.object.reference.binding.id);
|
|
1786
|
+
if (!sourceType)
|
|
1787
|
+
return undefined;
|
|
1788
|
+
const sourceProperties = getIrObjectTypePropertiesRust(sourceType, context);
|
|
1789
|
+
if (!sourceProperties)
|
|
1790
|
+
return undefined;
|
|
1791
|
+
const excluded = new Set(expression.excluded.flatMap((key) => (key.kind === 'named' ? [key.name] : [])));
|
|
1792
|
+
return sourceProperties.filter((property) => !excluded.has(property.name));
|
|
1793
|
+
}
|
|
1794
|
+
function emitObjectExpressionRust(expression, context) {
|
|
1795
|
+
if (expression.members.some((member) => member.kind === 'getAccessor')) {
|
|
1796
|
+
emissionError(context, 'object getters require target-specific accessor lowering');
|
|
1797
|
+
}
|
|
1798
|
+
const target = emitType(expression.type, context);
|
|
1799
|
+
const properties = getIrObjectConstructionPropertiesRust(expression.type, context);
|
|
1800
|
+
const members = expression.members.filter((member) => member.kind === 'property');
|
|
1801
|
+
const names = new Set();
|
|
1802
|
+
const fields = members.map((member) => {
|
|
1803
|
+
names.add(member.name);
|
|
1804
|
+
const property = properties?.find((candidate) => candidate.name === member.name);
|
|
1805
|
+
const value = emitExpression(member.value, context);
|
|
1806
|
+
return `${safeRustValueName(member.name)}: ${property?.optional ? `Some(${value})` : value},`;
|
|
1807
|
+
});
|
|
1808
|
+
for (const property of properties ?? []) {
|
|
1809
|
+
if (names.has(property.name))
|
|
1810
|
+
continue;
|
|
1811
|
+
fields.push(`${safeRustValueName(property.name)}: None,`);
|
|
1812
|
+
}
|
|
1813
|
+
return `${target} { ${fields.join(' ')} }`;
|
|
1814
|
+
}
|
|
1815
|
+
function inferIrExpressionTypeRust(expression, context) {
|
|
1816
|
+
switch (expression.kind) {
|
|
1817
|
+
case 'literal':
|
|
1818
|
+
if (expression.value === null)
|
|
1819
|
+
return { kind: 'null' };
|
|
1820
|
+
return typeof expression.value === 'string'
|
|
1821
|
+
? { kind: 'primitive', name: 'string' }
|
|
1822
|
+
: typeof expression.value === 'number'
|
|
1823
|
+
? { kind: 'primitive', name: 'number' }
|
|
1824
|
+
: { kind: 'primitive', name: 'boolean' };
|
|
1825
|
+
case 'cast':
|
|
1826
|
+
return expression.type;
|
|
1827
|
+
case 'call':
|
|
1828
|
+
return expression.semantics.resultType;
|
|
1829
|
+
case 'identifier':
|
|
1830
|
+
return expression.reference.kind === 'binding'
|
|
1831
|
+
? context.bindingTypes.get(expression.reference.binding.id)
|
|
1832
|
+
: undefined;
|
|
1833
|
+
case 'binary':
|
|
1834
|
+
case 'unary': {
|
|
1835
|
+
const domain = expression.semantics.result;
|
|
1836
|
+
return domain === 'bigint' ||
|
|
1837
|
+
domain === 'boolean' ||
|
|
1838
|
+
domain === 'number' ||
|
|
1839
|
+
domain === 'string' ||
|
|
1840
|
+
domain === 'symbol'
|
|
1841
|
+
? { kind: 'primitive', name: domain }
|
|
1842
|
+
: domain === 'null'
|
|
1843
|
+
? { kind: 'null' }
|
|
1844
|
+
: domain === 'undefined'
|
|
1845
|
+
? { kind: 'undefined' }
|
|
1846
|
+
: undefined;
|
|
1847
|
+
}
|
|
1848
|
+
case 'object':
|
|
1849
|
+
return expression.type;
|
|
1850
|
+
case 'property': {
|
|
1851
|
+
const binding = expression.member ? getCompilerRustAmbientMemberBinding(expression.member) : undefined;
|
|
1852
|
+
return binding?.kind === 'countingMethod' ? { kind: 'primitive', name: 'number' } : undefined;
|
|
1853
|
+
}
|
|
1854
|
+
default:
|
|
1855
|
+
return undefined;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
function getIrObjectConstructionPropertiesRust(type, context) {
|
|
1859
|
+
return getIrObjectTypePropertiesRust(type, context);
|
|
1860
|
+
}
|
|
1861
|
+
function getIrObjectTypeTargetNameRust(properties, context) {
|
|
1862
|
+
const shape = createIrObjectTypeShapeIdentity(properties);
|
|
1863
|
+
const existing = context.anonymousObjectRecords.get(shape);
|
|
1864
|
+
if (existing)
|
|
1865
|
+
return existing.name;
|
|
1866
|
+
const name = getGeneratedTargetNameRust('AnonymousObjectRecord', context);
|
|
1867
|
+
context.anonymousObjectRecords.set(shape, { name, properties });
|
|
1868
|
+
return name;
|
|
1869
|
+
}
|
|
1870
|
+
function getOrCreateCallableObjectRecordRust(type, context) {
|
|
1871
|
+
const callables = type.types.filter((member) => member.kind === 'function');
|
|
1872
|
+
if (callables.length !== 1)
|
|
1873
|
+
return undefined;
|
|
1874
|
+
const callable = callables[0];
|
|
1875
|
+
if (callable.typeParameters.length > 0) {
|
|
1876
|
+
emissionError(context, 'generic callable-object intersections require Rust monomorphization');
|
|
1877
|
+
}
|
|
1878
|
+
const shapes = type.types
|
|
1879
|
+
.filter((member) => member !== callable)
|
|
1880
|
+
.map((member) => getIrObjectTypePropertiesRust(member, context));
|
|
1881
|
+
if (shapes.length === 0 || shapes.some((shape) => !shape))
|
|
1882
|
+
return undefined;
|
|
1883
|
+
const properties = mergeIrObjectTypePropertiesRust(shapes.flatMap((shape) => shape));
|
|
1884
|
+
if (!properties)
|
|
1885
|
+
return undefined;
|
|
1886
|
+
const key = JSON.stringify({
|
|
1887
|
+
callable,
|
|
1888
|
+
parameters: context.activeTypeParameters.map((parameter) => parameter.binding.id),
|
|
1889
|
+
shape: createIrObjectTypeShapeIdentity(properties),
|
|
1890
|
+
});
|
|
1891
|
+
const existing = context.callableObjectRecords.get(key);
|
|
1892
|
+
if (existing)
|
|
1893
|
+
return existing;
|
|
1894
|
+
context.needsRcImport.add('Rc');
|
|
1895
|
+
const record = {
|
|
1896
|
+
callable: {
|
|
1897
|
+
parameters: callable.parameters.map((parameter) => {
|
|
1898
|
+
const emitted = emitType(parameter.type, context);
|
|
1899
|
+
return parameter.optional ? `Option<${emitted}>` : emitted;
|
|
1900
|
+
}),
|
|
1901
|
+
returns: emitType(callable.returns, context),
|
|
1902
|
+
},
|
|
1903
|
+
fields: properties.map((property) => ({
|
|
1904
|
+
name: safeRustValueName(property.name),
|
|
1905
|
+
optional: property.optional,
|
|
1906
|
+
rustType: emitType(property.type, context),
|
|
1907
|
+
})),
|
|
1908
|
+
name: getGeneratedTargetNameRust('AnonymousCallableObject', context),
|
|
1909
|
+
typeParameters: context.activeTypeParameters,
|
|
1910
|
+
};
|
|
1911
|
+
context.callableObjectRecords.set(key, record);
|
|
1912
|
+
return record;
|
|
1913
|
+
}
|
|
1914
|
+
function emitCallableObjectRecordRust(record, context) {
|
|
1915
|
+
const parameters = record.callable.parameters.join(', ');
|
|
1916
|
+
const signature = `dyn Fn(${parameters}) -> ${record.callable.returns}`;
|
|
1917
|
+
const typeParameters = emitTypeParameters(record.typeParameters, context);
|
|
1918
|
+
const typeArguments = emitTypeArguments(record.typeParameters, context);
|
|
1919
|
+
return [
|
|
1920
|
+
'#[derive(Clone)]',
|
|
1921
|
+
`pub struct ${record.name}${typeParameters} {`,
|
|
1922
|
+
` pub callback: Rc<${signature}>,`,
|
|
1923
|
+
...record.fields.map((field) => ` pub ${field.name}: ${field.optional ? `Option<${field.rustType}>` : field.rustType},`),
|
|
1924
|
+
'}',
|
|
1925
|
+
'',
|
|
1926
|
+
`impl${typeParameters} std::ops::Deref for ${record.name}${typeArguments} {`,
|
|
1927
|
+
` type Target = ${signature};`,
|
|
1928
|
+
'',
|
|
1929
|
+
' fn deref(&self) -> &Self::Target {',
|
|
1930
|
+
' self.callback.as_ref()',
|
|
1931
|
+
' }',
|
|
1932
|
+
'}',
|
|
1933
|
+
];
|
|
1934
|
+
}
|
|
1935
|
+
// A value Rust moves is invalidated at the site that consumes it, so a binding the source still
|
|
1936
|
+
// needs afterwards is cloned into the consuming position rather than handed over. Every emitted
|
|
1937
|
+
// record derives `Clone`, so this is always available. The election is per binding rather than per
|
|
1938
|
+
// use, so the last consumption clones as well: correct, at the cost of one copy the source did not
|
|
1939
|
+
// need, and a binding consumed once is left to move.
|
|
1940
|
+
function emitOwnedOperandRust(expression, context) {
|
|
1941
|
+
const source = emitExpression(expression, context);
|
|
1942
|
+
if (expression.kind === 'identifier' &&
|
|
1943
|
+
expression.reference.kind === 'binding' &&
|
|
1944
|
+
context.movedBindingIds.has(expression.reference.binding.id))
|
|
1945
|
+
return `${source}.clone()`;
|
|
1946
|
+
if (expression.kind === 'element' && !expression.optional && expression.semantics.receivers.includes('array'))
|
|
1947
|
+
return `${source}.clone()`;
|
|
1948
|
+
return source;
|
|
1949
|
+
}
|
|
1950
|
+
function emitReturnedExpressionRust(expression, context) {
|
|
1951
|
+
const source = emitExpression(expression, context);
|
|
1952
|
+
if (expression.kind === 'element' && !expression.optional && expression.semantics.receivers.includes('array'))
|
|
1953
|
+
return `${source}.clone()`;
|
|
1954
|
+
if (context.enclosingReturnType?.kind === 'function' && expression.kind === 'function') {
|
|
1955
|
+
context.needsRcImport.add('Rc');
|
|
1956
|
+
return emitCellCloneBlockRust(`Rc::new(move ${source})`, expression, context);
|
|
1957
|
+
}
|
|
1958
|
+
return source;
|
|
1959
|
+
}
|
|
1960
|
+
function collectIrModuleApiReferencedBindingIdsRust(module) {
|
|
1961
|
+
const ids = new Set();
|
|
1962
|
+
function collectFromType(type) {
|
|
1963
|
+
switch (type.kind) {
|
|
1964
|
+
case 'named':
|
|
1965
|
+
if (type.reference.kind === 'binding')
|
|
1966
|
+
ids.add(type.reference.binding.id);
|
|
1967
|
+
for (const arg of type.typeArguments)
|
|
1968
|
+
collectFromType(arg);
|
|
1969
|
+
break;
|
|
1970
|
+
case 'array':
|
|
1971
|
+
collectFromType(type.element);
|
|
1972
|
+
break;
|
|
1973
|
+
case 'conditionalFacet':
|
|
1974
|
+
collectFromType(type.check);
|
|
1975
|
+
collectFromType(type.facet);
|
|
1976
|
+
break;
|
|
1977
|
+
case 'function':
|
|
1978
|
+
for (const parameter of type.parameters)
|
|
1979
|
+
collectFromType(parameter.type);
|
|
1980
|
+
collectFromType(type.returns);
|
|
1981
|
+
break;
|
|
1982
|
+
case 'intersection':
|
|
1983
|
+
case 'union':
|
|
1984
|
+
for (const member of type.types)
|
|
1985
|
+
collectFromType(member);
|
|
1986
|
+
break;
|
|
1987
|
+
case 'object':
|
|
1988
|
+
for (const property of type.properties)
|
|
1989
|
+
collectFromType(property.type);
|
|
1990
|
+
break;
|
|
1991
|
+
case 'tuple':
|
|
1992
|
+
for (const element of type.elements)
|
|
1993
|
+
collectFromType(element.type);
|
|
1994
|
+
break;
|
|
1995
|
+
case 'indexedAccess':
|
|
1996
|
+
collectFromType(type.object);
|
|
1997
|
+
collectFromType(type.index);
|
|
1998
|
+
break;
|
|
1999
|
+
case 'keyof':
|
|
2000
|
+
collectFromType(type.type);
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
for (const declaration of module.declarations) {
|
|
2005
|
+
if (!declaration.exported)
|
|
2006
|
+
continue;
|
|
2007
|
+
if (declaration.kind === 'function') {
|
|
2008
|
+
for (const parameter of declaration.parameters)
|
|
2009
|
+
collectFromType(parameter.type);
|
|
2010
|
+
collectFromType(declaration.returns);
|
|
2011
|
+
}
|
|
2012
|
+
else if (declaration.kind === 'class') {
|
|
2013
|
+
for (const field of declaration.fields)
|
|
2014
|
+
if (field.visibility === 'public')
|
|
2015
|
+
collectFromType(field.type);
|
|
2016
|
+
for (const method of declaration.methods) {
|
|
2017
|
+
if (method.visibility !== 'public')
|
|
2018
|
+
continue;
|
|
2019
|
+
for (const parameter of method.parameters)
|
|
2020
|
+
collectFromType(parameter.type);
|
|
2021
|
+
collectFromType(method.returns);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
return ids;
|
|
2026
|
+
}
|
|
2027
|
+
function collectIrModuleArrayElementBindingIdsRust(module) {
|
|
2028
|
+
const candidates = new Set();
|
|
2029
|
+
const coalesceTargets = new Set();
|
|
2030
|
+
analyzeIrModuleTraversal(module, {
|
|
2031
|
+
variable(variable) {
|
|
2032
|
+
if ('binding' in variable &&
|
|
2033
|
+
variable.initializer?.kind === 'element' &&
|
|
2034
|
+
!variable.initializer.optional &&
|
|
2035
|
+
variable.initializer.semantics.receivers.includes('array')) {
|
|
2036
|
+
candidates.add(variable.binding.id);
|
|
2037
|
+
}
|
|
2038
|
+
return undefined;
|
|
2039
|
+
},
|
|
2040
|
+
expression(expression) {
|
|
2041
|
+
if (expression.kind === 'binary' &&
|
|
2042
|
+
expression.operator === '??' &&
|
|
2043
|
+
expression.left.kind === 'identifier' &&
|
|
2044
|
+
expression.left.reference.kind === 'binding') {
|
|
2045
|
+
coalesceTargets.add(expression.left.reference.binding.id);
|
|
2046
|
+
}
|
|
2047
|
+
return undefined;
|
|
2048
|
+
},
|
|
2049
|
+
});
|
|
2050
|
+
const ids = new Set();
|
|
2051
|
+
for (const id of candidates) {
|
|
2052
|
+
if (coalesceTargets.has(id))
|
|
2053
|
+
ids.add(id);
|
|
2054
|
+
}
|
|
2055
|
+
return ids;
|
|
2056
|
+
}
|
|
2057
|
+
function collectIrModuleBindingTypesRust(module) {
|
|
2058
|
+
const result = new Map();
|
|
2059
|
+
analyzeIrModuleTraversal(module, {
|
|
2060
|
+
parameter(parameter) {
|
|
2061
|
+
result.set(parameter.binding.id, parameter.type);
|
|
2062
|
+
},
|
|
2063
|
+
variable(variable) {
|
|
2064
|
+
if ('binding' in variable && variable.type) {
|
|
2065
|
+
result.set(variable.binding.id, variable.type);
|
|
2066
|
+
}
|
|
2067
|
+
},
|
|
2068
|
+
});
|
|
2069
|
+
return result;
|
|
2070
|
+
}
|
|
2071
|
+
// `unknown` has no single native Rust representation. A binding used exclusively through one
|
|
2072
|
+
// explicit source assertion does, however: the Rust API can expose that asserted type directly and
|
|
2073
|
+
// erase the assertion. Any unasserted use or disagreement leaves the binding opaque, so this never
|
|
2074
|
+
// guesses a dynamic conversion that the source did not perform.
|
|
2075
|
+
function collectAssertedUnknownBindingTypesRust(module, bindingTypes) {
|
|
2076
|
+
const candidates = new Map();
|
|
2077
|
+
const disqualified = new Set();
|
|
2078
|
+
const parameters = new Set();
|
|
2079
|
+
analyzeIrModuleTraversal(module, {
|
|
2080
|
+
parameter(parameter) {
|
|
2081
|
+
if (parameter.type.kind === 'unknown')
|
|
2082
|
+
parameters.add(parameter.binding.id);
|
|
2083
|
+
},
|
|
2084
|
+
});
|
|
2085
|
+
analyzeIrModuleTraversal(module, {
|
|
2086
|
+
expression(expression, path) {
|
|
2087
|
+
if (expression.kind !== 'identifier' || expression.reference.kind !== 'binding')
|
|
2088
|
+
return;
|
|
2089
|
+
const id = expression.reference.binding.id;
|
|
2090
|
+
if (!parameters.has(id) || bindingTypes.get(id)?.kind !== 'unknown')
|
|
2091
|
+
return;
|
|
2092
|
+
const parent = path.length > 0 ? getIrModuleTraversalPathValue(module, path.slice(0, -1)) : undefined;
|
|
2093
|
+
const asserted = parent &&
|
|
2094
|
+
typeof parent === 'object' &&
|
|
2095
|
+
'kind' in parent &&
|
|
2096
|
+
parent.kind === 'cast' &&
|
|
2097
|
+
'expression' in parent &&
|
|
2098
|
+
parent.expression === expression &&
|
|
2099
|
+
'type' in parent &&
|
|
2100
|
+
isIrTypeAssertedUnknownRepresentationRust(parent.type)
|
|
2101
|
+
? parent.type
|
|
2102
|
+
: undefined;
|
|
2103
|
+
if (!asserted) {
|
|
2104
|
+
disqualified.add(id);
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
const existing = candidates.get(id);
|
|
2108
|
+
if (existing && !areIrAssertedUnknownRepresentationsEqualRust(existing, asserted)) {
|
|
2109
|
+
disqualified.add(id);
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
candidates.set(id, asserted);
|
|
2113
|
+
},
|
|
2114
|
+
});
|
|
2115
|
+
for (const id of disqualified)
|
|
2116
|
+
candidates.delete(id);
|
|
2117
|
+
return candidates;
|
|
2118
|
+
}
|
|
2119
|
+
function isIrTypeAssertedUnknownRepresentationRust(type) {
|
|
2120
|
+
if (!type || typeof type !== 'object' || !('kind' in type) || type.kind !== 'primitive')
|
|
2121
|
+
return false;
|
|
2122
|
+
return 'name' in type && (type.name === 'boolean' || type.name === 'number' || type.name === 'string');
|
|
2123
|
+
}
|
|
2124
|
+
function areIrAssertedUnknownRepresentationsEqualRust(left, right) {
|
|
2125
|
+
return left.kind === 'primitive' && right.kind === 'primitive' && left.name === right.name;
|
|
2126
|
+
}
|
|
2127
|
+
function resolvePrimitiveUnionEnumRust(type, context) {
|
|
2128
|
+
if (type.kind !== 'union')
|
|
2129
|
+
return undefined;
|
|
2130
|
+
const concrete = type.types.filter((t) => t.kind !== 'null' && t.kind !== 'undefined');
|
|
2131
|
+
if (concrete.length < 2)
|
|
2132
|
+
return undefined;
|
|
2133
|
+
return getOrCreatePrimitiveUnionEnumRust(concrete, context);
|
|
2134
|
+
}
|
|
2135
|
+
function resolveDualSentinelUnionEnumRust(type, context) {
|
|
2136
|
+
return type.kind === 'union' && hasIrTypeNullMemberRust(type) && hasIrTypeUndefinedMemberRust(type)
|
|
2137
|
+
? getOrCreateAnonymousUnionEnumRust(type.types, context)
|
|
2138
|
+
: undefined;
|
|
2139
|
+
}
|
|
2140
|
+
function getIrExpressionDualSentinelUnionRust(expression, context) {
|
|
2141
|
+
if (expression.kind !== 'identifier' || expression.reference.kind !== 'binding')
|
|
2142
|
+
return undefined;
|
|
2143
|
+
const type = context.bindingTypes.get(expression.reference.binding.id);
|
|
2144
|
+
return type ? resolveDualSentinelUnionEnumRust(type, context) : undefined;
|
|
2145
|
+
}
|
|
2146
|
+
function emitDualSentinelUnionConstructionRust(expression, targetEnum, context) {
|
|
2147
|
+
if (expression.kind === 'conditional') {
|
|
2148
|
+
const condition = emitExpression(expression.condition, context);
|
|
2149
|
+
const whenTrue = emitDualSentinelUnionConstructionRust(expression.whenTrue, targetEnum, context);
|
|
2150
|
+
const whenFalse = emitDualSentinelUnionConstructionRust(expression.whenFalse, targetEnum, context);
|
|
2151
|
+
return whenTrue && whenFalse ? `if ${condition} { ${whenTrue} } else { ${whenFalse} }` : undefined;
|
|
2152
|
+
}
|
|
2153
|
+
if (expression.kind === 'literal' && expression.value === null)
|
|
2154
|
+
return `${targetEnum.name}::Null`;
|
|
2155
|
+
if (expression.kind === 'undefinedValue' ||
|
|
2156
|
+
(expression.kind === 'identifier' &&
|
|
2157
|
+
expression.reference.kind === 'ambient' &&
|
|
2158
|
+
expression.reference.name === 'undefined')) {
|
|
2159
|
+
return `${targetEnum.name}::Undefined`;
|
|
2160
|
+
}
|
|
2161
|
+
const sourceUnion = getIrExpressionDualSentinelUnionRust(expression, context);
|
|
2162
|
+
if (sourceUnion?.name === targetEnum.name)
|
|
2163
|
+
return emitOwnedOperandRust(expression, context);
|
|
2164
|
+
const payloads = targetEnum.variants.filter((variant) => variant.kind === 'tuple');
|
|
2165
|
+
if (payloads.length === 1) {
|
|
2166
|
+
return `${targetEnum.name}::${payloads[0].name}(${emitOwnedOperandRust(expression, context)})`;
|
|
2167
|
+
}
|
|
2168
|
+
const primitiveKind = inferIrExpressionPrimitiveKindRust(expression, context);
|
|
2169
|
+
const preferred = primitiveKind
|
|
2170
|
+
? getGeneralUnionVariantNameRust({ kind: 'primitive', name: primitiveKind }, context)
|
|
2171
|
+
: undefined;
|
|
2172
|
+
const payload = preferred ? payloads.find((variant) => variant.name === preferred) : undefined;
|
|
2173
|
+
return payload ? `${targetEnum.name}::${payload.name}(${emitOwnedOperandRust(expression, context)})` : undefined;
|
|
2174
|
+
}
|
|
2175
|
+
function inferIrExpressionPrimitiveKindRust(expression, context) {
|
|
2176
|
+
switch (expression.kind) {
|
|
2177
|
+
case 'literal':
|
|
2178
|
+
return typeof expression.value === 'string'
|
|
2179
|
+
? 'string'
|
|
2180
|
+
: typeof expression.value === 'number'
|
|
2181
|
+
? 'number'
|
|
2182
|
+
: typeof expression.value === 'boolean'
|
|
2183
|
+
? 'boolean'
|
|
2184
|
+
: undefined;
|
|
2185
|
+
case 'template':
|
|
2186
|
+
return 'string';
|
|
2187
|
+
case 'binary': {
|
|
2188
|
+
const result = expression.semantics.result;
|
|
2189
|
+
return result === 'string' || result === 'number' || result === 'boolean' ? result : undefined;
|
|
2190
|
+
}
|
|
2191
|
+
case 'unary': {
|
|
2192
|
+
const result = expression.semantics.result;
|
|
2193
|
+
return result === 'string' || result === 'number' || result === 'boolean' ? result : undefined;
|
|
2194
|
+
}
|
|
2195
|
+
case 'call': {
|
|
2196
|
+
const resultType = expression.semantics.resultType;
|
|
2197
|
+
return resultType.kind === 'primitive' &&
|
|
2198
|
+
(resultType.name === 'string' || resultType.name === 'number' || resultType.name === 'boolean')
|
|
2199
|
+
? resultType.name
|
|
2200
|
+
: undefined;
|
|
2201
|
+
}
|
|
2202
|
+
case 'cast':
|
|
2203
|
+
return expression.type.kind === 'primitive' &&
|
|
2204
|
+
(expression.type.name === 'string' || expression.type.name === 'number' || expression.type.name === 'boolean')
|
|
2205
|
+
? expression.type.name
|
|
2206
|
+
: undefined;
|
|
2207
|
+
case 'identifier': {
|
|
2208
|
+
if (expression.reference.kind !== 'binding')
|
|
2209
|
+
return undefined;
|
|
2210
|
+
const bindingType = context.bindingTypes.get(expression.reference.binding.id);
|
|
2211
|
+
if (!bindingType || bindingType.kind !== 'primitive')
|
|
2212
|
+
return undefined;
|
|
2213
|
+
return bindingType.name === 'string' || bindingType.name === 'number' || bindingType.name === 'boolean'
|
|
2214
|
+
? bindingType.name
|
|
2215
|
+
: undefined;
|
|
2216
|
+
}
|
|
2217
|
+
default:
|
|
2218
|
+
return undefined;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
function emitPrimitiveUnionConstructionRust(expression, targetEnum, context) {
|
|
2222
|
+
if (expression.kind === 'conditional') {
|
|
2223
|
+
const condition = emitExpression(expression.condition, context);
|
|
2224
|
+
const whenTrue = emitPrimitiveUnionConstructionRust(expression.whenTrue, targetEnum, context);
|
|
2225
|
+
const whenFalse = emitPrimitiveUnionConstructionRust(expression.whenFalse, targetEnum, context);
|
|
2226
|
+
if (whenTrue === undefined || whenFalse === undefined)
|
|
2227
|
+
return undefined;
|
|
2228
|
+
return `if ${condition} { ${whenTrue} } else { ${whenFalse} }`;
|
|
2229
|
+
}
|
|
2230
|
+
const emitted = normalizeSourceTextGrouping(emitOwnedOperandRust(expression, context));
|
|
2231
|
+
const primitiveKind = inferIrExpressionPrimitiveKindRust(expression, context);
|
|
2232
|
+
if (!primitiveKind)
|
|
2233
|
+
return undefined;
|
|
2234
|
+
const variant = targetEnum.variants.find((v) => v.primitiveKind === primitiveKind);
|
|
2235
|
+
if (!variant)
|
|
2236
|
+
return undefined;
|
|
2237
|
+
return `${targetEnum.name}::${variant.variantName}(${emitted})`;
|
|
2238
|
+
}
|
|
2239
|
+
function collectCellCapturedBindingIdsRust(expression, context) {
|
|
2240
|
+
if (expression.kind !== 'function' ||
|
|
2241
|
+
(context.cellWrappedBindingIds.size === 0 && context.refCellWrappedBindingIds.size === 0))
|
|
2242
|
+
return [];
|
|
2243
|
+
const found = new Set();
|
|
2244
|
+
const observer = {
|
|
2245
|
+
expression(expr) {
|
|
2246
|
+
if (expr.kind === 'identifier' &&
|
|
2247
|
+
expr.reference.kind === 'binding' &&
|
|
2248
|
+
(context.cellWrappedBindingIds.has(expr.reference.binding.id) ||
|
|
2249
|
+
context.refCellWrappedBindingIds.has(expr.reference.binding.id))) {
|
|
2250
|
+
found.add(expr.reference.binding.id);
|
|
2251
|
+
}
|
|
2252
|
+
if (expr.kind === 'function')
|
|
2253
|
+
return false;
|
|
2254
|
+
return undefined;
|
|
2255
|
+
},
|
|
2256
|
+
};
|
|
2257
|
+
expression.body.forEach((stmt) => analyzeIrStatementSubtreeTraversal(stmt, observer));
|
|
2258
|
+
return [...found];
|
|
2259
|
+
}
|
|
2260
|
+
function emitCellCloneBlockRust(rcExpression, closureExpression, context) {
|
|
2261
|
+
const capturedCellIds = collectCellCapturedBindingIdsRust(closureExpression, context);
|
|
2262
|
+
if (capturedCellIds.length === 0)
|
|
2263
|
+
return rcExpression;
|
|
2264
|
+
const clones = capturedCellIds.map((id) => {
|
|
2265
|
+
const name = context.targetNames.get(id) ?? id;
|
|
2266
|
+
return ` let ${name} = Rc::clone(&${name});`;
|
|
2267
|
+
});
|
|
2268
|
+
return `{\n${clones.join('\n')}\n ${rcExpression}\n}`;
|
|
2269
|
+
}
|
|
2270
|
+
function emitClosureWithCellClonesRust(expression, context) {
|
|
2271
|
+
const source = emitExpression(expression, context);
|
|
2272
|
+
return emitCellCloneBlockRust(`Rc::new(move ${source})`, expression, context);
|
|
2273
|
+
}
|
|
2274
|
+
// A value lent to a callee that mutates through it. An argument that is already a mutable borrow is
|
|
2275
|
+
// passed as it stands, because Rust reborrows it: taking a reference to it again would hand the
|
|
2276
|
+
// callee a reference to the reference.
|
|
2277
|
+
function emitLentOperandRust(expression, context) {
|
|
2278
|
+
const source = emitExpression(expression, context);
|
|
2279
|
+
return expression.kind === 'identifier' &&
|
|
2280
|
+
expression.reference.kind === 'binding' &&
|
|
2281
|
+
context.referentMutatedParameterIds.has(expression.reference.binding.id)
|
|
2282
|
+
? source
|
|
2283
|
+
: `&mut ${source}`;
|
|
2284
|
+
}
|
|
2285
|
+
// A closure an iterator adaptor hands a reference to. The source wrote it for the element, so the
|
|
2286
|
+
// reference is destructured away at the binding — which Rust allows for a value it can copy, and
|
|
2287
|
+
// which is why an element it cannot copy is refused rather than silently borrowed.
|
|
2288
|
+
function emitBorrowedElementClosureRust(expression, context) {
|
|
2289
|
+
if (expression?.kind !== 'function') {
|
|
2290
|
+
return emissionError(context, 'filtering requires a closure written where the predicate is passed');
|
|
2291
|
+
}
|
|
2292
|
+
const parameters = expression.parameters.map((parameter, index) => {
|
|
2293
|
+
if (index > 0)
|
|
2294
|
+
return getBindingTargetNameRust(parameter.binding, context);
|
|
2295
|
+
if (!isIrTypeCopyValueRust(parameter.type)) {
|
|
2296
|
+
emissionError(context, 'filtering an element Rust cannot copy requires a borrowed predicate lowering');
|
|
2297
|
+
}
|
|
2298
|
+
return `&${getBindingTargetNameRust(parameter.binding, context)}`;
|
|
2299
|
+
});
|
|
2300
|
+
const body = expression.expression
|
|
2301
|
+
? normalizeSourceTextGrouping(emitExpression(expression.expression, context))
|
|
2302
|
+
: `{\n${indentSourceLines(emitStatements(expression.body, context)).join('\n')}\n}`;
|
|
2303
|
+
return `|${parameters.join(', ')}| ${body}`;
|
|
2304
|
+
}
|
|
2305
|
+
function emitIteratorCallbackWrapperRust(expression, emittedCallee, context) {
|
|
2306
|
+
const name = getGeneratedTargetNameRust('x', context);
|
|
2307
|
+
return `|${name}| ${emittedCallee}(${name})`;
|
|
2308
|
+
}
|
|
2309
|
+
function emitArrayPredicatePositionRust(receiver, callback, emittedCallback, targetName, context) {
|
|
2310
|
+
let parameterCount;
|
|
2311
|
+
if (callback?.kind === 'function') {
|
|
2312
|
+
parameterCount = callback.parameters.length;
|
|
2313
|
+
}
|
|
2314
|
+
else if (callback?.kind === 'identifier' && callback.reference.kind === 'binding') {
|
|
2315
|
+
const callbackType = context.bindingTypes.get(callback.reference.binding.id);
|
|
2316
|
+
if (callbackType?.kind === 'function')
|
|
2317
|
+
parameterCount = callbackType.parameters.length;
|
|
2318
|
+
}
|
|
2319
|
+
if (!callback || !emittedCallback || parameterCount === undefined || parameterCount < 1 || parameterCount > 2) {
|
|
2320
|
+
emissionError(context, 'array findIndex requires a statically known one- or two-parameter Rust predicate');
|
|
2321
|
+
}
|
|
2322
|
+
const index = getGeneratedTargetNameRust('predicate_index', context);
|
|
2323
|
+
const element = getGeneratedTargetNameRust('predicate_element', context);
|
|
2324
|
+
const arguments_ = [`${element}.clone()`, ...(parameterCount === 2 ? [`${index} as f64`] : [])];
|
|
2325
|
+
return `${receiver}.iter().enumerate().${targetName}(|(${index}, ${element})| (${emittedCallback})(${arguments_.join(', ')})).map(|i| i as f64).unwrap_or(-1.0)`;
|
|
2326
|
+
}
|
|
2327
|
+
function isIrSelfFieldNonCopyRust(fieldName, context) {
|
|
2328
|
+
for (const declaration of context.module.declarations) {
|
|
2329
|
+
if (declaration.kind !== 'class')
|
|
2330
|
+
continue;
|
|
2331
|
+
const field = declaration.fields.find((candidate) => !candidate.static && candidate.name === fieldName);
|
|
2332
|
+
if (field)
|
|
2333
|
+
return !isIrTypeCopyValueRust(field.type);
|
|
2334
|
+
}
|
|
2335
|
+
return false;
|
|
2336
|
+
}
|
|
2337
|
+
function isIrTypeCopyValueRust(type) {
|
|
2338
|
+
return type.kind === 'primitive' && (type.name === 'boolean' || type.name === 'number');
|
|
2339
|
+
}
|
|
2340
|
+
// An index, in the form Rust counts with. A literal whole number is written as one; anything else is
|
|
2341
|
+
// a value in the neutral numeric type and has to be converted.
|
|
2342
|
+
function emitIndexOperandRust(expression, context) {
|
|
2343
|
+
return expression.kind === 'literal' && typeof expression.value === 'number' && Number.isInteger(expression.value)
|
|
2344
|
+
? String(expression.value)
|
|
2345
|
+
: `${emitExpression(expression, context)} as usize`;
|
|
2346
|
+
}
|
|
2347
|
+
function emitBorrowedNarrowedReceiverRust(object, context) {
|
|
2348
|
+
if (object.kind !== 'identifier' || object.reference.kind !== 'binding')
|
|
2349
|
+
return undefined;
|
|
2350
|
+
if (object.presence !== 'narrowedPresent')
|
|
2351
|
+
return undefined;
|
|
2352
|
+
if (!context.nullableBindingIds.has(object.reference.binding.id))
|
|
2353
|
+
return undefined;
|
|
2354
|
+
return `${emitIdentifierReferenceRust(object.reference, context)}.as_ref().unwrap()`;
|
|
2355
|
+
}
|
|
2356
|
+
// A value on its way into a binding that can hold nothing. The source language stores a value and an
|
|
2357
|
+
// absence in one place without saying so; Rust's `Option` says so, and a present value has to be
|
|
2358
|
+
// wrapped to enter it. A value that is already optional passes through: it is already the shape.
|
|
2359
|
+
function emitOptionalTargetOperandRust(target, value, context) {
|
|
2360
|
+
const source = emitExpression(value, context);
|
|
2361
|
+
if (target.kind !== 'identifier' || target.reference.kind !== 'binding')
|
|
2362
|
+
return source;
|
|
2363
|
+
if (!context.nullableBindingIds.has(target.reference.binding.id))
|
|
2364
|
+
return source;
|
|
2365
|
+
const alreadyOptional = isIrExpressionOptionShapedRust(value, context);
|
|
2366
|
+
return alreadyOptional ? source : `Some(${source})`;
|
|
2367
|
+
}
|
|
2368
|
+
// Text in a position Rust borrows rather than owns. A literal is already a `&str` before it is
|
|
2369
|
+
// owned, so the ownership is simply not taken; anything else is borrowed from the value it names.
|
|
2370
|
+
function emitBorrowedTextRust(expression, context) {
|
|
2371
|
+
return expression.kind === 'literal' && typeof expression.value === 'string'
|
|
2372
|
+
? JSON.stringify(expression.value)
|
|
2373
|
+
: `&${emitExpression(expression, context)}`;
|
|
2374
|
+
}
|
|
2375
|
+
// A constructor that does nothing but fill its own fields is a Rust struct literal, which is the one
|
|
2376
|
+
// constructor shape Rust has. The body must assign every instance field exactly once and read none of
|
|
2377
|
+
// them back: a field literal cannot see a field the same literal is still building.
|
|
2378
|
+
function getIrClassConstructorFieldAssignmentsRust(declaration, statelessBase) {
|
|
2379
|
+
const constructor = declaration.classConstructor;
|
|
2380
|
+
const instanceFields = declaration.fields.filter((field) => !field.static);
|
|
2381
|
+
if (!constructor || instanceFields.length === 0)
|
|
2382
|
+
return undefined;
|
|
2383
|
+
if (instanceFields.some((field) => field.initializer))
|
|
2384
|
+
return undefined;
|
|
2385
|
+
const assigned = [];
|
|
2386
|
+
for (const statement of constructor.body) {
|
|
2387
|
+
// A base that holds no state has nothing to initialize, so the call that would have initialized
|
|
2388
|
+
// it does nothing and leaves nothing for the struct literal to say.
|
|
2389
|
+
if (statelessBase && isIrStatementSuperConstructorCallRust(statement))
|
|
2390
|
+
continue;
|
|
2391
|
+
if (statement.kind !== 'expression' || statement.expression.kind !== 'assignment')
|
|
2392
|
+
return undefined;
|
|
2393
|
+
const { left, operator, right } = statement.expression;
|
|
2394
|
+
if (operator !== '=' || left.kind !== 'property' || left.object.kind !== 'identifier')
|
|
2395
|
+
return undefined;
|
|
2396
|
+
if (left.object.reference.kind !== 'this' || left.optional)
|
|
2397
|
+
return undefined;
|
|
2398
|
+
if (assigned.some((field) => field.name === left.name))
|
|
2399
|
+
return undefined;
|
|
2400
|
+
if (hasIrExpressionThisReferenceRust(right))
|
|
2401
|
+
return undefined;
|
|
2402
|
+
assigned.push({ name: left.name, value: right });
|
|
2403
|
+
}
|
|
2404
|
+
return assigned.length === instanceFields.length &&
|
|
2405
|
+
instanceFields.every((field) => assigned.some((entry) => entry.name === field.name))
|
|
2406
|
+
? assigned
|
|
2407
|
+
: undefined;
|
|
2408
|
+
}
|
|
2409
|
+
function getIrClassCompositionConstructorRust(declaration, base) {
|
|
2410
|
+
const constructor = declaration.classConstructor;
|
|
2411
|
+
const instanceFields = declaration.fields.filter((field) => !field.static);
|
|
2412
|
+
if (!constructor || instanceFields.length === 0)
|
|
2413
|
+
return undefined;
|
|
2414
|
+
let superArguments;
|
|
2415
|
+
const childFields = [];
|
|
2416
|
+
for (const statement of constructor.body) {
|
|
2417
|
+
if (!superArguments && isIrStatementSuperConstructorCallRust(statement)) {
|
|
2418
|
+
const call = statement.expression;
|
|
2419
|
+
superArguments = call.arguments;
|
|
2420
|
+
continue;
|
|
2421
|
+
}
|
|
2422
|
+
if (statement.kind !== 'expression' || statement.expression.kind !== 'assignment')
|
|
2423
|
+
return undefined;
|
|
2424
|
+
const { left, operator, right } = statement.expression;
|
|
2425
|
+
if (operator !== '=' || left.kind !== 'property' || left.object.kind !== 'identifier')
|
|
2426
|
+
return undefined;
|
|
2427
|
+
if (left.object.reference.kind !== 'this' || left.optional)
|
|
2428
|
+
return undefined;
|
|
2429
|
+
if (base.fields.some((field) => !field.static && field.name === left.name))
|
|
2430
|
+
return undefined;
|
|
2431
|
+
if (childFields.some((field) => field.name === left.name))
|
|
2432
|
+
return undefined;
|
|
2433
|
+
if (hasIrExpressionThisReferenceRust(right))
|
|
2434
|
+
return undefined;
|
|
2435
|
+
childFields.push({ name: left.name, value: right });
|
|
2436
|
+
}
|
|
2437
|
+
if (!superArguments)
|
|
2438
|
+
return undefined;
|
|
2439
|
+
return childFields.length === instanceFields.length &&
|
|
2440
|
+
instanceFields.every((field) => childFields.some((entry) => entry.name === field.name))
|
|
2441
|
+
? { superArguments, childFields }
|
|
2442
|
+
: undefined;
|
|
2443
|
+
}
|
|
2444
|
+
function isIrCompositionBaseMemberRust(name, base) {
|
|
2445
|
+
return (base.fields.some((field) => !field.static && field.name === name) ||
|
|
2446
|
+
base.methods.some((method) => !method.static && method.name === name));
|
|
2447
|
+
}
|
|
2448
|
+
function isIrStatementSuperConstructorCallRust(statement) {
|
|
2449
|
+
return (statement.kind === 'expression' &&
|
|
2450
|
+
statement.expression.kind === 'call' &&
|
|
2451
|
+
statement.expression.callee.kind === 'identifier' &&
|
|
2452
|
+
statement.expression.callee.reference.kind === 'super');
|
|
2453
|
+
}
|
|
2454
|
+
function collectAsyncTryStatementsRust(module, analysis) {
|
|
2455
|
+
const result = new Set();
|
|
2456
|
+
for (const machine of analysis.machines) {
|
|
2457
|
+
for (const state of machine.states) {
|
|
2458
|
+
for (const step of state.steps) {
|
|
2459
|
+
if (step.kind !== 'suspend' || step.rejectState === undefined)
|
|
2460
|
+
continue;
|
|
2461
|
+
const tryStatement = getEnclosingTryStatementRust(module, step.path);
|
|
2462
|
+
if (tryStatement)
|
|
2463
|
+
result.add(tryStatement);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
return result;
|
|
2468
|
+
}
|
|
2469
|
+
function getEnclosingTryStatementRust(module, suspensionPath) {
|
|
2470
|
+
for (let i = suspensionPath.length - 1; i >= 0; i--) {
|
|
2471
|
+
if (suspensionPath[i] === 'tryBody') {
|
|
2472
|
+
return getIrModuleTraversalPathValue(module, suspensionPath.slice(0, i));
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
return undefined;
|
|
2476
|
+
}
|
|
2477
|
+
function emitAsyncTryCatchRust(statement, context) {
|
|
2478
|
+
const tryStatements = statement.tryBody.kind === 'block' ? statement.tryBody.statements : [statement.tryBody];
|
|
2479
|
+
const awaitIndex = tryStatements.findIndex((s) => (s.kind === 'expression' && s.expression.kind === 'assignment' && s.expression.right.kind === 'await') ||
|
|
2480
|
+
(s.kind === 'return' && s.expression?.kind === 'await'));
|
|
2481
|
+
if (awaitIndex === -1) {
|
|
2482
|
+
emissionError(context, 'async try/catch requires a recognizable await assignment or return');
|
|
2483
|
+
return [];
|
|
2484
|
+
}
|
|
2485
|
+
const awaitStatement = tryStatements[awaitIndex];
|
|
2486
|
+
const preStatements = tryStatements.slice(0, awaitIndex);
|
|
2487
|
+
const postStatements = tryStatements.slice(awaitIndex + 1);
|
|
2488
|
+
const isReturn = awaitStatement.kind === 'return';
|
|
2489
|
+
let awaitTarget;
|
|
2490
|
+
let assignmentExpression;
|
|
2491
|
+
if (awaitStatement.kind === 'return' && awaitStatement.expression?.kind === 'await') {
|
|
2492
|
+
awaitTarget = awaitStatement.expression.expression;
|
|
2493
|
+
}
|
|
2494
|
+
else if (awaitStatement.kind === 'expression' &&
|
|
2495
|
+
awaitStatement.expression.kind === 'assignment' &&
|
|
2496
|
+
awaitStatement.expression.right.kind === 'await') {
|
|
2497
|
+
assignmentExpression = awaitStatement.expression;
|
|
2498
|
+
awaitTarget = awaitStatement.expression.right.expression;
|
|
2499
|
+
}
|
|
2500
|
+
if (!awaitTarget) {
|
|
2501
|
+
emissionError(context, 'async try/catch requires a direct await expression');
|
|
2502
|
+
return [];
|
|
2503
|
+
}
|
|
2504
|
+
const settleExpr = `${emitOwnedOperandRust(awaitTarget, context)}.settle()`;
|
|
2505
|
+
const lines = [];
|
|
2506
|
+
lines.push(...emitStatements(preStatements, context));
|
|
2507
|
+
if (statement.catchClause) {
|
|
2508
|
+
const catchBinding = statement.catchClause.binding ? safeRustValueName(statement.catchClause.binding.name) : '_';
|
|
2509
|
+
lines.push(`match ${settleExpr} {`);
|
|
2510
|
+
if (isReturn) {
|
|
2511
|
+
lines.push(...indentSourceLines([
|
|
2512
|
+
'Ok(__value) => {',
|
|
2513
|
+
...indentSourceLines([...emitStatements(postStatements, context), 'return __value;']),
|
|
2514
|
+
'}',
|
|
2515
|
+
]));
|
|
2516
|
+
}
|
|
2517
|
+
else {
|
|
2518
|
+
const okBody = [];
|
|
2519
|
+
if (assignmentExpression) {
|
|
2520
|
+
okBody.push(`${emitExpression(assignmentExpression.left, context)} ${emitAssignmentOperatorRust(assignmentExpression.operator, assignmentExpression.semantics, context)} __value;`);
|
|
2521
|
+
}
|
|
2522
|
+
okBody.push(...emitStatements(postStatements, context));
|
|
2523
|
+
lines.push(...indentSourceLines(['Ok(__value) => {', ...indentSourceLines(okBody), '}']));
|
|
2524
|
+
}
|
|
2525
|
+
lines.push(...indentSourceLines([
|
|
2526
|
+
`Err(${catchBinding}) => {`,
|
|
2527
|
+
...indentSourceLines(emitStatementBody(statement.catchClause.body, context)),
|
|
2528
|
+
'}',
|
|
2529
|
+
]));
|
|
2530
|
+
lines.push('}');
|
|
2531
|
+
if (statement.finallyBody) {
|
|
2532
|
+
lines.push(...emitStatementBody(statement.finallyBody, context));
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
else if (statement.finallyBody) {
|
|
2536
|
+
lines.push(`let __try_result = ${settleExpr};`);
|
|
2537
|
+
lines.push(...emitStatementBody(statement.finallyBody, context));
|
|
2538
|
+
if (isReturn) {
|
|
2539
|
+
lines.push('match __try_result {');
|
|
2540
|
+
lines.push(...indentSourceLines([
|
|
2541
|
+
'Ok(__value) => return __value,',
|
|
2542
|
+
'Err(__error) => panic!("unhandled task rejection: {}", __error),',
|
|
2543
|
+
]));
|
|
2544
|
+
lines.push('}');
|
|
2545
|
+
}
|
|
2546
|
+
else {
|
|
2547
|
+
lines.push('match __try_result {');
|
|
2548
|
+
const okBody = [];
|
|
2549
|
+
if (assignmentExpression) {
|
|
2550
|
+
okBody.push(`${emitExpression(assignmentExpression.left, context)} ${emitAssignmentOperatorRust(assignmentExpression.operator, assignmentExpression.semantics, context)} __value;`);
|
|
2551
|
+
}
|
|
2552
|
+
okBody.push(...emitStatements(postStatements, context));
|
|
2553
|
+
lines.push(...indentSourceLines([
|
|
2554
|
+
'Ok(__value) => {',
|
|
2555
|
+
...indentSourceLines(okBody),
|
|
2556
|
+
'}',
|
|
2557
|
+
'Err(__error) => panic!("unhandled task rejection: {}", __error),',
|
|
2558
|
+
]));
|
|
2559
|
+
lines.push('}');
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
else {
|
|
2563
|
+
emissionError(context, 'async try without catch or finally');
|
|
2564
|
+
}
|
|
2565
|
+
return lines;
|
|
2566
|
+
}
|
|
2567
|
+
function hasIrExpressionThisReferenceRust(expression) {
|
|
2568
|
+
let found = false;
|
|
2569
|
+
analyzeIrStatementSubtreeTraversal({ expression, kind: 'expression' }, {
|
|
2570
|
+
expression(node) {
|
|
2571
|
+
if (node.kind === 'identifier' && node.reference.kind === 'this')
|
|
2572
|
+
found = true;
|
|
2573
|
+
return undefined;
|
|
2574
|
+
},
|
|
2575
|
+
});
|
|
2576
|
+
return found;
|
|
2577
|
+
}
|
|
2578
|
+
function emitParameter(parameter, context) {
|
|
2579
|
+
const parameterType = context.assertedUnknownBindingTypes.get(parameter.binding.id) ?? parameter.type;
|
|
2580
|
+
// The source mutates what this parameter names, and the caller sees the change. Moving the value in
|
|
2581
|
+
// would mutate a copy and drop it — the same source, a different meaning — so the parameter is
|
|
2582
|
+
// borrowed mutably and every call site lends rather than gives.
|
|
2583
|
+
if (context.referentMutatedParameterIds.has(parameter.binding.id)) {
|
|
2584
|
+
if (parameter.initializer || parameter.optional || parameter.rest) {
|
|
2585
|
+
emissionError(context, `parameter ${parameter.binding.name} is mutated through and cannot also be optional or variadic in Rust`);
|
|
2586
|
+
}
|
|
2587
|
+
return `${getBindingTargetNameRust(parameter.binding, context)}: &mut ${emitType(parameterType, context)}`;
|
|
2588
|
+
}
|
|
2589
|
+
// A parameter the body assigns to is a local binding in Rust as much as in the source language, and
|
|
2590
|
+
// Rust will not accept the assignment without `mut`. Emitting it unconditionally would instead earn
|
|
2591
|
+
// an unused-mut warning on every parameter that is only read.
|
|
2592
|
+
const binding = `${context.reboundBindingIds.has(parameter.binding.id) ? 'mut ' : ''}${getBindingTargetNameRust(parameter.binding, context)}`;
|
|
2593
|
+
if (parameter.initializer) {
|
|
2594
|
+
return `${binding}: Option<${emitType(parameterType, context)}>`;
|
|
2595
|
+
}
|
|
2596
|
+
if (parameter.optional) {
|
|
2597
|
+
const type = emitType(parameterType, context);
|
|
2598
|
+
if (hasIrTypeNullMemberRust(parameter.type) && hasIrTypeUndefinedMemberRust(parameter.type)) {
|
|
2599
|
+
emissionError(context, 'optional parameters containing both null and undefined require distinct Rust sentinels');
|
|
2600
|
+
}
|
|
2601
|
+
const optionalType = hasIrTypeUndefinedMemberRust(parameter.type) && !hasIrTypeNullMemberRust(parameter.type)
|
|
2602
|
+
? type
|
|
2603
|
+
: `Option<${type}>`;
|
|
2604
|
+
return `${binding}: ${optionalType}`;
|
|
2605
|
+
}
|
|
2606
|
+
if (parameter.rest)
|
|
2607
|
+
return `${binding}: ${emitType(parameterType, context)}`;
|
|
2608
|
+
return `${binding}: ${emitType(parameterType, context)}`;
|
|
2609
|
+
}
|
|
2610
|
+
function emitRecord(targetName, properties, typeParameters, exported, context) {
|
|
2611
|
+
// A record a public function names has to be at least as visible as that function, and a record
|
|
2612
|
+
// the source did not export is still named by one often enough that hiding it only produces a
|
|
2613
|
+
// private-interface warning. What leaves the crate is the crate root's decision, not this module's.
|
|
2614
|
+
void exported;
|
|
2615
|
+
const typeContext = { ...context, activeTypeParameters: typeParameters };
|
|
2616
|
+
const lines = [
|
|
2617
|
+
emitRustRecordDerive(properties.map((property) => property.type), typeContext),
|
|
2618
|
+
`pub struct ${targetName}${emitTypeParameters(typeParameters, context)} {`,
|
|
2619
|
+
];
|
|
2620
|
+
for (const property of properties) {
|
|
2621
|
+
const type = emitType(property.type, typeContext);
|
|
2622
|
+
lines.push(` pub ${safeRustValueName(property.name)}: ${property.optional ? `Option<${type}>` : type},`);
|
|
2623
|
+
}
|
|
2624
|
+
lines.push('}');
|
|
2625
|
+
return lines;
|
|
2626
|
+
}
|
|
2627
|
+
function emitStatementValueExpressionRust(expression, context) {
|
|
2628
|
+
if (expression.callee.kind !== 'function' || expression.arguments.length > 0) {
|
|
2629
|
+
emissionError(context, 'statement-value call requires a zero-argument function carrier');
|
|
2630
|
+
}
|
|
2631
|
+
const completion = expression.callee.body.at(-1);
|
|
2632
|
+
if (completion?.kind !== 'return' || !completion.expression) {
|
|
2633
|
+
emissionError(context, 'statement-value call requires a final value return');
|
|
2634
|
+
}
|
|
2635
|
+
const statements = emitStatements(expression.callee.body.slice(0, -1), context);
|
|
2636
|
+
return `{ ${[...statements, emitExpression(completion.expression, context)].join(' ')} }`;
|
|
2637
|
+
}
|
|
2638
|
+
function emitStatement(statement, context) {
|
|
2639
|
+
switch (statement.kind) {
|
|
2640
|
+
case 'block':
|
|
2641
|
+
return [
|
|
2642
|
+
`${emitControlFlowLabelRust(statement.label)}{`,
|
|
2643
|
+
...indentSourceLines(emitStatements(statement.statements, context)),
|
|
2644
|
+
'}',
|
|
2645
|
+
];
|
|
2646
|
+
case 'break':
|
|
2647
|
+
return [`break${statement.target ? ` ${emitControlFlowTargetRust(statement.target)}` : ''};`];
|
|
2648
|
+
case 'continue':
|
|
2649
|
+
return [`continue${statement.target ? ` ${emitControlFlowTargetRust(statement.target)}` : ''};`];
|
|
2650
|
+
case 'do':
|
|
2651
|
+
return [
|
|
2652
|
+
`${emitControlFlowLabelRust(statement.label)}loop {`,
|
|
2653
|
+
...indentSourceLines(emitStatementBody(statement.body, context)),
|
|
2654
|
+
` if !(${emitExpression(statement.condition, context)}) { break; }`,
|
|
2655
|
+
'}',
|
|
2656
|
+
];
|
|
2657
|
+
case 'expression':
|
|
2658
|
+
return [`${emitExpression(statement.expression, context)};`];
|
|
2659
|
+
case 'for':
|
|
2660
|
+
emissionError(context, 'C-style for loops require control-flow lowering before Rust emission');
|
|
2661
|
+
case 'forIn':
|
|
2662
|
+
if ('pattern' in statement.variable)
|
|
2663
|
+
emissionError(context, 'binding patterns require destructuring lowering before Rust emission');
|
|
2664
|
+
if (!statement.keyPlan) {
|
|
2665
|
+
emissionError(context, 'object key iteration requires closed key evidence');
|
|
2666
|
+
}
|
|
2667
|
+
if (statement.keyPlan.evaluation === 'preserve') {
|
|
2668
|
+
emissionError(context, 'effectful object key iteration requires Rust structural-object evaluation lowering');
|
|
2669
|
+
}
|
|
2670
|
+
return [
|
|
2671
|
+
`${emitControlFlowLabelRust(statement.label)}for ${statement.variable.mutable ? 'mut ' : ''}${getBindingTargetNameRust(statement.variable.binding, context)} in [${statement.keyPlan.keys.map((key) => `${JSON.stringify(key)}.to_owned()`).join(', ')}] {`,
|
|
2672
|
+
...indentSourceLines(emitStatementBody(statement.body, context)),
|
|
2673
|
+
'}',
|
|
2674
|
+
];
|
|
2675
|
+
case 'forOf': {
|
|
2676
|
+
if (statement.await)
|
|
2677
|
+
emissionError(context, 'async iteration requires Flight task lowering');
|
|
2678
|
+
if ('pattern' in statement.variable)
|
|
2679
|
+
emissionError(context, 'binding patterns require destructuring lowering before Rust emission');
|
|
2680
|
+
const iterableRust = emitExpression(statement.iterable, context);
|
|
2681
|
+
const borrowPrefix = statement.iterable.kind === 'element' ? '&' : '';
|
|
2682
|
+
return [
|
|
2683
|
+
`${emitControlFlowLabelRust(statement.label)}for ${statement.variable.mutable ? 'mut ' : ''}${getBindingTargetNameRust(statement.variable.binding, context)} in ${borrowPrefix}${iterableRust} {`,
|
|
2684
|
+
...indentSourceLines(emitStatementBody(statement.body, context)),
|
|
2685
|
+
'}',
|
|
2686
|
+
];
|
|
2687
|
+
}
|
|
2688
|
+
case 'if': {
|
|
2689
|
+
const lines = [
|
|
2690
|
+
`if ${normalizeSourceTextGrouping(emitExpression(statement.condition, context))} {`,
|
|
2691
|
+
...indentSourceLines(emitStatementBody(statement.consequent, context)),
|
|
2692
|
+
'}',
|
|
2693
|
+
];
|
|
2694
|
+
if (statement.otherwise)
|
|
2695
|
+
lines.push('else {', ...indentSourceLines(emitStatementBody(statement.otherwise, context)), '}');
|
|
2696
|
+
return lines;
|
|
2697
|
+
}
|
|
2698
|
+
case 'return':
|
|
2699
|
+
// Comparing against `None` is not narrowing. Returning a binding that can be absent from a
|
|
2700
|
+
// function that cannot return one is Rust that does not compile, so it refuses here.
|
|
2701
|
+
if (!context.returnsAbsent &&
|
|
2702
|
+
statement.expression?.kind === 'identifier' &&
|
|
2703
|
+
statement.expression.reference.kind === 'binding' &&
|
|
2704
|
+
statement.expression.presence !== 'narrowedPresent' &&
|
|
2705
|
+
context.nullableBindingIds.has(statement.expression.reference.binding.id)) {
|
|
2706
|
+
emissionError(context, 'returning a nullable binding requires Rust narrowing evidence');
|
|
2707
|
+
}
|
|
2708
|
+
if (statement.expression && context.enclosingReturnType) {
|
|
2709
|
+
const dualSentinelUnion = resolveDualSentinelUnionEnumRust(context.enclosingReturnType, context);
|
|
2710
|
+
if (dualSentinelUnion) {
|
|
2711
|
+
const wrapped = emitDualSentinelUnionConstructionRust(statement.expression, dualSentinelUnion, context);
|
|
2712
|
+
if (wrapped)
|
|
2713
|
+
return [`return ${wrapped};`];
|
|
2714
|
+
}
|
|
2715
|
+
const numericEnum = getIrTypeNumericEnumNamespaceNameRust(context.enclosingReturnType, context);
|
|
2716
|
+
if (numericEnum) {
|
|
2717
|
+
const expressionEnum = getIrExpressionNumericEnumNamespaceNameRust(statement.expression, context);
|
|
2718
|
+
const emitted = emitReturnedExpressionRust(statement.expression, context);
|
|
2719
|
+
return [`return ${expressionEnum === numericEnum ? emitted : `${numericEnum}((${emitted}) as i32)`};`];
|
|
2720
|
+
}
|
|
2721
|
+
const targetEnum = resolvePrimitiveUnionEnumRust(context.enclosingReturnType, context);
|
|
2722
|
+
if (targetEnum) {
|
|
2723
|
+
if (statement.expression.kind === 'identifier' &&
|
|
2724
|
+
statement.expression.reference.kind === 'binding' &&
|
|
2725
|
+
context.primitiveUnionBindingIds.get(statement.expression.reference.binding.id) === targetEnum.name) {
|
|
2726
|
+
return [`return ${emitIdentifierReferenceRust(statement.expression.reference, context)};`];
|
|
2727
|
+
}
|
|
2728
|
+
const wrapped = emitPrimitiveUnionConstructionRust(statement.expression, targetEnum, context);
|
|
2729
|
+
if (wrapped)
|
|
2730
|
+
return [`return ${wrapped};`];
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
return [
|
|
2734
|
+
`return${statement.expression ? ` ${normalizeSourceTextGrouping(emitReturnedExpressionRust(statement.expression, context))}` : ''};`,
|
|
2735
|
+
];
|
|
2736
|
+
case 'switch': {
|
|
2737
|
+
const name = getGeneratedTargetNameRust('switch_value', context);
|
|
2738
|
+
const cases = statement.cases.filter((switchCase) => switchCase.expression);
|
|
2739
|
+
const otherwise = statement.cases.find((switchCase) => !switchCase.expression);
|
|
2740
|
+
const lines = [`let ${name} = ${emitExpression(statement.expression, context)};`];
|
|
2741
|
+
cases.forEach((switchCase, index) => {
|
|
2742
|
+
lines.push(`${index > 0 ? 'else ' : ''}if ${name} == ${emitExpression(switchCase.expression, context)} {`, ...indentSourceLines(emitIrSwitchCaseStatementsRust(switchCase, statement.label, context)), '}');
|
|
2743
|
+
});
|
|
2744
|
+
if (otherwise) {
|
|
2745
|
+
if (cases.length > 0)
|
|
2746
|
+
lines.push('else {');
|
|
2747
|
+
lines.push(...indentSourceLines(emitIrSwitchCaseStatementsRust(otherwise, statement.label, context), cases.length > 0 ? 1 : 0));
|
|
2748
|
+
if (cases.length > 0)
|
|
2749
|
+
lines.push('}');
|
|
2750
|
+
}
|
|
2751
|
+
else if (cases.length > 0) {
|
|
2752
|
+
lines.push('else {', ' unreachable!();', '}');
|
|
2753
|
+
}
|
|
2754
|
+
return [`${emitControlFlowLabelRust(statement.label)}{`, ...indentSourceLines(lines), '}'];
|
|
2755
|
+
}
|
|
2756
|
+
case 'throw': {
|
|
2757
|
+
const thrown = statement.expression;
|
|
2758
|
+
if (thrown.kind === 'new' && thrown.callee.kind === 'identifier' && thrown.arguments.length === 1) {
|
|
2759
|
+
return [`panic!("{}", ${emitExpression(thrown.arguments[0], context)});`];
|
|
2760
|
+
}
|
|
2761
|
+
return [`panic!("{:?}", ${emitExpression(thrown, context)});`];
|
|
2762
|
+
}
|
|
2763
|
+
case 'try': {
|
|
2764
|
+
if (context.asyncTryStatements.has(statement)) {
|
|
2765
|
+
return emitAsyncTryCatchRust(statement, context);
|
|
2766
|
+
}
|
|
2767
|
+
if (statement.finallyBody) {
|
|
2768
|
+
emissionError(context, 'synchronous try/finally requires catch_unwind with resume_unwind');
|
|
2769
|
+
}
|
|
2770
|
+
const catchBinding = statement.catchClause
|
|
2771
|
+
? statement.catchClause.binding
|
|
2772
|
+
? safeRustValueName(statement.catchClause.binding.name)
|
|
2773
|
+
: '_'
|
|
2774
|
+
: '_';
|
|
2775
|
+
const matchArms = statement.catchClause
|
|
2776
|
+
? [
|
|
2777
|
+
'Ok(__catch_result) => return __catch_result,',
|
|
2778
|
+
`Err(${catchBinding}) => {`,
|
|
2779
|
+
...indentSourceLines(emitStatementBody(statement.catchClause.body, context)),
|
|
2780
|
+
'}',
|
|
2781
|
+
]
|
|
2782
|
+
: ['Ok(_) => {}', 'Err(_) => {}'];
|
|
2783
|
+
return [
|
|
2784
|
+
'match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {',
|
|
2785
|
+
...indentSourceLines(emitStatementBody(statement.tryBody, context)),
|
|
2786
|
+
'})) {',
|
|
2787
|
+
...indentSourceLines(matchArms),
|
|
2788
|
+
'}',
|
|
2789
|
+
];
|
|
2790
|
+
}
|
|
2791
|
+
case 'variable':
|
|
2792
|
+
return statement.declarations.map((variable) => emitVariable(variable, context));
|
|
2793
|
+
case 'while':
|
|
2794
|
+
// Rust spells a loop with no exit condition `loop`, and warns on `while true` because the two
|
|
2795
|
+
// differ to the borrow checker: only `loop` tells it the body always runs.
|
|
2796
|
+
const condition = normalizeSourceTextGrouping(emitExpression(statement.condition, context));
|
|
2797
|
+
return [
|
|
2798
|
+
`${emitControlFlowLabelRust(statement.label)}${condition === 'true' ? 'loop' : `while ${condition}`} {`,
|
|
2799
|
+
...indentSourceLines(emitStatementBody(statement.body, context)),
|
|
2800
|
+
'}',
|
|
2801
|
+
];
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
function emitIrSwitchCaseStatementsRust(switchCase, switchLabel, context) {
|
|
2805
|
+
const last = switchCase.statements.at(-1);
|
|
2806
|
+
const localBreak = last?.kind === 'break' && (!last.target || (switchLabel && last.target.id === switchLabel.id));
|
|
2807
|
+
return emitStatements(localBreak ? switchCase.statements.slice(0, -1) : switchCase.statements, context);
|
|
2808
|
+
}
|
|
2809
|
+
function emitControlFlowLabelRust(label) {
|
|
2810
|
+
return label ? `${emitControlFlowTargetRust(label)}: ` : '';
|
|
2811
|
+
}
|
|
2812
|
+
function emitControlFlowTargetRust(label) {
|
|
2813
|
+
return `'${safeRustValueName(label.name)}`;
|
|
2814
|
+
}
|
|
2815
|
+
function emitStatementBody(statement, context) {
|
|
2816
|
+
return statement.kind === 'block'
|
|
2817
|
+
? emitStatements(statement.statements, context)
|
|
2818
|
+
: emitStatements([statement], context);
|
|
2819
|
+
}
|
|
2820
|
+
function emitStatements(statements, context) {
|
|
2821
|
+
return statements.flatMap((statement) => emitStatement(statement, context));
|
|
2822
|
+
}
|
|
2823
|
+
function emitType(type, context) {
|
|
2824
|
+
switch (type.kind) {
|
|
2825
|
+
case 'array':
|
|
2826
|
+
return `Vec<${emitType(type.element, context)}>`;
|
|
2827
|
+
case 'function': {
|
|
2828
|
+
context.needsRcImport.add('Rc');
|
|
2829
|
+
const parameters = type.parameters.map((parameter) => emitType(parameter.type, context));
|
|
2830
|
+
const returns = emitType(type.returns, context);
|
|
2831
|
+
return `Rc<dyn Fn(${parameters.join(', ')}) -> ${returns}>`;
|
|
2832
|
+
}
|
|
2833
|
+
case 'indexedAccess':
|
|
2834
|
+
case 'conditionalFacet':
|
|
2835
|
+
case 'typeOf':
|
|
2836
|
+
return opaqueHostType(context);
|
|
2837
|
+
case 'keyof': {
|
|
2838
|
+
const resolved = getIrKeyofTypeRust(type.type, context);
|
|
2839
|
+
if (!resolved)
|
|
2840
|
+
return opaqueHostType(context);
|
|
2841
|
+
return emitType(resolved, context);
|
|
2842
|
+
}
|
|
2843
|
+
case 'intersection': {
|
|
2844
|
+
const scalarDomain = getIrTypePrimitiveDomainRust(type, context);
|
|
2845
|
+
if (scalarDomain)
|
|
2846
|
+
return emitType({ kind: 'primitive', name: scalarDomain }, context);
|
|
2847
|
+
const callableObject = getOrCreateCallableObjectRecordRust(type, context);
|
|
2848
|
+
if (callableObject) {
|
|
2849
|
+
return `${callableObject.name}${emitTypeArguments(callableObject.typeParameters, context)}`;
|
|
2850
|
+
}
|
|
2851
|
+
const properties = getIrObjectTypePropertiesRust(type, context);
|
|
2852
|
+
if (properties)
|
|
2853
|
+
return getIrObjectTypeTargetNameRust(properties, context);
|
|
2854
|
+
emissionError(context, 'intersection types require Rust record or trait lowering');
|
|
2855
|
+
}
|
|
2856
|
+
case 'literal':
|
|
2857
|
+
return typeof type.value === 'boolean' ? 'bool' : typeof type.value === 'number' ? 'f64' : 'String';
|
|
2858
|
+
case 'named': {
|
|
2859
|
+
const sourceName = type.reference.kind === 'ambient' ? type.reference.name : undefined;
|
|
2860
|
+
if ((sourceName === 'Readonly' || sourceName === 'Required') && type.typeArguments[0]) {
|
|
2861
|
+
return emitType(type.typeArguments[0], context);
|
|
2862
|
+
}
|
|
2863
|
+
if (sourceName === 'NoInfer' && type.typeArguments.length === 1 && type.typeArguments[0]) {
|
|
2864
|
+
return emitType(type.typeArguments[0], context);
|
|
2865
|
+
}
|
|
2866
|
+
if (sourceName === 'Exclude' || sourceName === 'Extract') {
|
|
2867
|
+
const projected = getIrFilteredTypeRust(sourceName, type.typeArguments, context);
|
|
2868
|
+
if (!projected)
|
|
2869
|
+
emissionError(context, `${sourceName} types require closed Rust type computation lowering`);
|
|
2870
|
+
return emitType(projected, context);
|
|
2871
|
+
}
|
|
2872
|
+
if (sourceName === 'Partial' || sourceName === 'Pick' || sourceName === 'Omit') {
|
|
2873
|
+
const properties = getIrObjectTypePropertiesRust(type, context);
|
|
2874
|
+
if (!properties)
|
|
2875
|
+
emissionError(context, `${sourceName}<T> requires a statically resolvable Rust object shape`);
|
|
2876
|
+
return getIrObjectTypeTargetNameRust(properties, context);
|
|
2877
|
+
}
|
|
2878
|
+
const mapped = getTypeReferenceTargetNameRust(type, context);
|
|
2879
|
+
const arguments_ = type.typeArguments.map((argument) => emitType(argument, context));
|
|
2880
|
+
return `${mapped}${arguments_.length > 0 ? `<${arguments_.join(', ')}>` : ''}`;
|
|
2881
|
+
}
|
|
2882
|
+
case 'never':
|
|
2883
|
+
return '!';
|
|
2884
|
+
case 'null':
|
|
2885
|
+
case 'undefined':
|
|
2886
|
+
return '()';
|
|
2887
|
+
case 'object':
|
|
2888
|
+
return getIrObjectTypeTargetNameRust(type.properties, context);
|
|
2889
|
+
case 'primitive':
|
|
2890
|
+
if (type.name === 'symbol')
|
|
2891
|
+
return recordRuntimeTypeRust('FlightSymbol', context);
|
|
2892
|
+
return { bigint: 'i64', boolean: 'bool', number: 'f64', string: 'String', symbol: 'FlightSymbol', void: '()' }[type.name];
|
|
2893
|
+
case 'tuple': {
|
|
2894
|
+
const elements = type.elements.map((element) => {
|
|
2895
|
+
const emitted = emitType(element.type, context);
|
|
2896
|
+
return element.optional ? `Option<${emitted}>` : emitted;
|
|
2897
|
+
});
|
|
2898
|
+
return `(${elements.join(', ')}${elements.length === 1 ? ',' : ''})`;
|
|
2899
|
+
}
|
|
2900
|
+
case 'union': {
|
|
2901
|
+
const concrete = type.types.filter((item) => item.kind !== 'null' && item.kind !== 'undefined');
|
|
2902
|
+
const optional = concrete.length !== type.types.length;
|
|
2903
|
+
if (hasIrTypeNullMemberRust(type) && hasIrTypeUndefinedMemberRust(type)) {
|
|
2904
|
+
const union = getOrCreateAnonymousUnionEnumRust(type.types, context);
|
|
2905
|
+
return `${union.name}${emitTypeArguments(union.typeParameters, context)}`;
|
|
2906
|
+
}
|
|
2907
|
+
if (concrete.length === 1 && concrete.length !== type.types.length)
|
|
2908
|
+
return `Option<${emitType(concrete[0], context)}>`;
|
|
2909
|
+
const primitiveDomain = getIrUnionPrimitiveDomainRust(concrete, context);
|
|
2910
|
+
if (primitiveDomain) {
|
|
2911
|
+
const emitted = emitType({ kind: 'primitive', name: primitiveDomain }, context);
|
|
2912
|
+
return optional ? `Option<${emitted}>` : emitted;
|
|
2913
|
+
}
|
|
2914
|
+
const primitiveEnum = getOrCreatePrimitiveUnionEnumRust(concrete, context);
|
|
2915
|
+
if (primitiveEnum)
|
|
2916
|
+
return optional ? `Option<${primitiveEnum.name}>` : primitiveEnum.name;
|
|
2917
|
+
const generalEnum = getOrCreateAnonymousUnionEnumRust(concrete, context);
|
|
2918
|
+
const emitted = `${generalEnum.name}${emitTypeArguments(generalEnum.typeParameters, context)}`;
|
|
2919
|
+
return optional ? `Option<${emitted}>` : emitted;
|
|
2920
|
+
}
|
|
2921
|
+
case 'unknown':
|
|
2922
|
+
return opaqueHostType(context);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
// TypeScript's object utilities and intersections are representation decisions in Rust: once every
|
|
2926
|
+
// participating declaration is closed, the result is one concrete record. Keep the resolver local
|
|
2927
|
+
// to the backend because it decides Rust storage, but consume the shared substitution machinery so
|
|
2928
|
+
// generic aliases and inherited interfaces do not acquire a second set of type-argument rules.
|
|
2929
|
+
function getIrObjectTypePropertiesRust(type, context, module = context.module, resolving = new Set()) {
|
|
2930
|
+
if (type.kind === 'object')
|
|
2931
|
+
return type.properties;
|
|
2932
|
+
if (type.kind === 'intersection') {
|
|
2933
|
+
const shapes = type.types.map((member) => getIrObjectTypePropertiesRust(member, context, module, resolving));
|
|
2934
|
+
return shapes.some((shape) => !shape)
|
|
2935
|
+
? undefined
|
|
2936
|
+
: mergeIrObjectTypePropertiesRust(shapes.flatMap((shape) => shape));
|
|
2937
|
+
}
|
|
2938
|
+
if (type.kind !== 'named')
|
|
2939
|
+
return undefined;
|
|
2940
|
+
if (type.reference.kind === 'ambient') {
|
|
2941
|
+
const utility = type.reference.name;
|
|
2942
|
+
if (utility === 'Record') {
|
|
2943
|
+
if (type.typeArguments.length !== 2 || !type.typeArguments[0] || !type.typeArguments[1])
|
|
2944
|
+
return undefined;
|
|
2945
|
+
const keys = getIrObjectProjectionKeysRust(type.typeArguments[0], context, module, resolving);
|
|
2946
|
+
if (!keys)
|
|
2947
|
+
return undefined;
|
|
2948
|
+
return [...keys].map((name) => ({
|
|
2949
|
+
name,
|
|
2950
|
+
optional: false,
|
|
2951
|
+
readonly: false,
|
|
2952
|
+
type: type.typeArguments[1],
|
|
2953
|
+
}));
|
|
2954
|
+
}
|
|
2955
|
+
if (utility === 'NoInfer' || utility === 'Partial' || utility === 'Readonly' || utility === 'Required') {
|
|
2956
|
+
if (type.typeArguments.length !== 1 || !type.typeArguments[0])
|
|
2957
|
+
return undefined;
|
|
2958
|
+
const properties = getIrObjectTypePropertiesRust(type.typeArguments[0], context, module, resolving);
|
|
2959
|
+
if (!properties)
|
|
2960
|
+
return undefined;
|
|
2961
|
+
return properties.map((property) => ({
|
|
2962
|
+
...property,
|
|
2963
|
+
...(utility === 'Partial' ? { optional: true } : {}),
|
|
2964
|
+
...(utility === 'Readonly' ? { readonly: true } : {}),
|
|
2965
|
+
...(utility === 'Required' ? { optional: false } : {}),
|
|
2966
|
+
}));
|
|
2967
|
+
}
|
|
2968
|
+
if (utility === 'Exclude' || utility === 'Extract') {
|
|
2969
|
+
const projected = getIrFilteredTypeRust(utility, type.typeArguments, context, module, resolving);
|
|
2970
|
+
return projected ? getIrObjectTypePropertiesRust(projected, context, module, resolving) : undefined;
|
|
2971
|
+
}
|
|
2972
|
+
if (utility !== 'Omit' && utility !== 'Pick')
|
|
2973
|
+
return undefined;
|
|
2974
|
+
if (type.typeArguments.length !== 2 || !type.typeArguments[0] || !type.typeArguments[1])
|
|
2975
|
+
return undefined;
|
|
2976
|
+
const properties = getIrObjectTypePropertiesRust(type.typeArguments[0], context, module, resolving);
|
|
2977
|
+
const keys = getIrObjectProjectionKeysRust(type.typeArguments[1], context, module, resolving);
|
|
2978
|
+
if (!properties || !keys)
|
|
2979
|
+
return undefined;
|
|
2980
|
+
return properties.filter((property) => (utility === 'Pick') === keys.has(property.name));
|
|
2981
|
+
}
|
|
2982
|
+
if (type.reference.path.length > 0)
|
|
2983
|
+
return undefined;
|
|
2984
|
+
if (type.reference.binding.space !== 'type' || type.reference.binding.kind === 'typeParameter')
|
|
2985
|
+
return undefined;
|
|
2986
|
+
const location = getIrNamedTypeDeclarationLocationRust(type.reference.binding, context, module);
|
|
2987
|
+
if (!location)
|
|
2988
|
+
return undefined;
|
|
2989
|
+
const key = `${location.module.packageName}\0${location.module.source}\0${location.declaration.binding.id}`;
|
|
2990
|
+
if (resolving.has(key))
|
|
2991
|
+
return undefined;
|
|
2992
|
+
const active = new Set(resolving).add(key);
|
|
2993
|
+
let plan;
|
|
2994
|
+
try {
|
|
2995
|
+
plan = createIrTypeParameterSubstitutionPlan(location.declaration.typeParameters, type.typeArguments);
|
|
2996
|
+
}
|
|
2997
|
+
catch (error) {
|
|
2998
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
2999
|
+
return undefined;
|
|
3000
|
+
throw error;
|
|
3001
|
+
}
|
|
3002
|
+
if (location.declaration.kind === 'typeAlias') {
|
|
3003
|
+
let resolved;
|
|
3004
|
+
try {
|
|
3005
|
+
resolved = resolveIrTypeStructuralSubstitution(location.declaration.type, plan);
|
|
3006
|
+
}
|
|
3007
|
+
catch (error) {
|
|
3008
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3009
|
+
return undefined;
|
|
3010
|
+
throw error;
|
|
3011
|
+
}
|
|
3012
|
+
return getIrObjectTypePropertiesRust(resolved, context, location.module, active);
|
|
3013
|
+
}
|
|
3014
|
+
const inherited = location.declaration.extends.map((reference) => {
|
|
3015
|
+
let resolved;
|
|
3016
|
+
try {
|
|
3017
|
+
resolved = resolveIrTypeStructuralSubstitution(reference, plan);
|
|
3018
|
+
}
|
|
3019
|
+
catch (error) {
|
|
3020
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3021
|
+
return undefined;
|
|
3022
|
+
throw error;
|
|
3023
|
+
}
|
|
3024
|
+
return getIrObjectTypePropertiesRust(resolved, context, location.module, active);
|
|
3025
|
+
});
|
|
3026
|
+
if (inherited.some((properties) => !properties))
|
|
3027
|
+
return undefined;
|
|
3028
|
+
let own;
|
|
3029
|
+
try {
|
|
3030
|
+
own = location.declaration.properties.map((property) => ({
|
|
3031
|
+
...property,
|
|
3032
|
+
type: resolveIrTypeStructuralSubstitution(property.type, plan),
|
|
3033
|
+
}));
|
|
3034
|
+
}
|
|
3035
|
+
catch (error) {
|
|
3036
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3037
|
+
return undefined;
|
|
3038
|
+
throw error;
|
|
3039
|
+
}
|
|
3040
|
+
return mergeIrObjectTypePropertiesRust([...inherited.flatMap((properties) => properties), ...own]);
|
|
3041
|
+
}
|
|
3042
|
+
function mergeIrObjectTypePropertiesRust(properties) {
|
|
3043
|
+
const merged = new Map();
|
|
3044
|
+
for (const property of properties) {
|
|
3045
|
+
const existing = merged.get(property.name);
|
|
3046
|
+
if (!existing) {
|
|
3047
|
+
merged.set(property.name, { ...property });
|
|
3048
|
+
continue;
|
|
3049
|
+
}
|
|
3050
|
+
if (JSON.stringify(existing.computedKey) !== JSON.stringify(property.computedKey) ||
|
|
3051
|
+
existing.phantom !== property.phantom ||
|
|
3052
|
+
existing.role !== property.role) {
|
|
3053
|
+
return undefined;
|
|
3054
|
+
}
|
|
3055
|
+
const type = JSON.stringify(existing.type) === JSON.stringify(property.type)
|
|
3056
|
+
? existing.type
|
|
3057
|
+
: createIrIntersectionTypeRust(existing.type, property.type);
|
|
3058
|
+
merged.set(property.name, {
|
|
3059
|
+
...existing,
|
|
3060
|
+
optional: existing.optional && property.optional,
|
|
3061
|
+
readonly: existing.readonly && property.readonly,
|
|
3062
|
+
type,
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
return [...merged.values()];
|
|
3066
|
+
}
|
|
3067
|
+
function getIrObjectProjectionKeysRust(type, context, module, resolving) {
|
|
3068
|
+
const members = getIrClosedTypeMembersRust(type, context, module, resolving);
|
|
3069
|
+
if (!members || members.some((member) => member.kind !== 'literal' || typeof member.value === 'boolean')) {
|
|
3070
|
+
return undefined;
|
|
3071
|
+
}
|
|
3072
|
+
return new Set(members.map((member) => String(member.value)));
|
|
3073
|
+
}
|
|
3074
|
+
function getIrKeyofTypeRust(type, context) {
|
|
3075
|
+
const properties = getIrObjectTypePropertiesRust(type, context);
|
|
3076
|
+
if (!properties)
|
|
3077
|
+
return undefined;
|
|
3078
|
+
const keys = [];
|
|
3079
|
+
if (properties.some((property) => !property.computedKey && !property.phantom)) {
|
|
3080
|
+
keys.push({ kind: 'primitive', name: 'string' });
|
|
3081
|
+
}
|
|
3082
|
+
if (properties.some((property) => property.computedKey && !property.phantom)) {
|
|
3083
|
+
keys.push({ kind: 'primitive', name: 'symbol' });
|
|
3084
|
+
}
|
|
3085
|
+
return createIrClosedTypeUnionRust(keys);
|
|
3086
|
+
}
|
|
3087
|
+
function getIrFilteredTypeRust(utility, typeArguments, context, module = context.module, resolving = new Set()) {
|
|
3088
|
+
if (typeArguments.length !== 2 || !typeArguments[0] || !typeArguments[1])
|
|
3089
|
+
return undefined;
|
|
3090
|
+
const included = getIrClosedTypeMembersRust(typeArguments[0], context, module, resolving);
|
|
3091
|
+
const filters = getIrClosedTypeMembersRust(typeArguments[1], context, module, resolving);
|
|
3092
|
+
if (!included || !filters)
|
|
3093
|
+
return undefined;
|
|
3094
|
+
const retained = [];
|
|
3095
|
+
for (const member of included) {
|
|
3096
|
+
const matches = filters.map((filter) => isIrTypeAssignableForFilterRust(member, filter, context, module, resolving));
|
|
3097
|
+
if (!matches.includes(true) && matches.includes(undefined))
|
|
3098
|
+
return undefined;
|
|
3099
|
+
const matched = matches.includes(true);
|
|
3100
|
+
if ((utility === 'Extract') === matched)
|
|
3101
|
+
retained.push(member);
|
|
3102
|
+
}
|
|
3103
|
+
return createIrClosedTypeUnionRust(retained);
|
|
3104
|
+
}
|
|
3105
|
+
function getIrClosedTypeMembersRust(type, context, module = context.module, resolving = new Set()) {
|
|
3106
|
+
if (type.kind === 'never')
|
|
3107
|
+
return [];
|
|
3108
|
+
if (type.kind === 'union') {
|
|
3109
|
+
const members = type.types.map((member) => getIrClosedTypeMembersRust(member, context, module, resolving));
|
|
3110
|
+
return members.some((member) => !member) ? undefined : members.flatMap((member) => member);
|
|
3111
|
+
}
|
|
3112
|
+
if (type.kind === 'keyof') {
|
|
3113
|
+
const resolved = getIrKeyofTypeRustInModule(type.type, context, module, resolving);
|
|
3114
|
+
return resolved ? getIrClosedTypeMembersRust(resolved, context, module, resolving) : undefined;
|
|
3115
|
+
}
|
|
3116
|
+
if (type.kind === 'typeOf') {
|
|
3117
|
+
const resolved = getIrTypeOfValueTypeRust(type, context, module);
|
|
3118
|
+
return resolved ? getIrClosedTypeMembersRust(resolved, context, module, resolving) : undefined;
|
|
3119
|
+
}
|
|
3120
|
+
if (type.kind === 'named' && type.reference.kind === 'binding' && type.reference.path.length === 0) {
|
|
3121
|
+
if (type.reference.binding.space !== 'type' || type.reference.binding.kind === 'typeParameter')
|
|
3122
|
+
return undefined;
|
|
3123
|
+
const location = getIrNamedTypeDeclarationLocationRust(type.reference.binding, context, module);
|
|
3124
|
+
if (location?.declaration.kind === 'typeAlias') {
|
|
3125
|
+
const key = `${location.module.packageName}\0${location.module.source}\0${location.declaration.binding.id}`;
|
|
3126
|
+
if (resolving.has(key))
|
|
3127
|
+
return undefined;
|
|
3128
|
+
try {
|
|
3129
|
+
const plan = createIrTypeParameterSubstitutionPlan(location.declaration.typeParameters, type.typeArguments);
|
|
3130
|
+
const resolved = resolveIrTypeStructuralSubstitution(location.declaration.type, plan);
|
|
3131
|
+
return getIrClosedTypeMembersRust(resolved, context, location.module, new Set(resolving).add(key));
|
|
3132
|
+
}
|
|
3133
|
+
catch (error) {
|
|
3134
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3135
|
+
return undefined;
|
|
3136
|
+
throw error;
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
if (type.kind === 'conditionalFacet' || type.kind === 'indexedAccess' || type.kind === 'unknown') {
|
|
3141
|
+
return undefined;
|
|
3142
|
+
}
|
|
3143
|
+
return [type];
|
|
3144
|
+
}
|
|
3145
|
+
function getIrTypeOfValueTypeRust(type, context, module) {
|
|
3146
|
+
if (type.reference.kind !== 'binding' || type.reference.path.length > 0)
|
|
3147
|
+
return undefined;
|
|
3148
|
+
const binding = type.reference.binding;
|
|
3149
|
+
const local = module.declarations.find((declaration) => declaration.kind === 'variable' && 'binding' in declaration && declaration.binding.id === binding.id);
|
|
3150
|
+
if (local?.kind === 'variable' && 'binding' in local)
|
|
3151
|
+
return getIrVariableTypeRust(local);
|
|
3152
|
+
const imported = module.imports
|
|
3153
|
+
.flatMap((item) => item.bindings.map((candidate) => ({ candidate, specifier: item.specifier })))
|
|
3154
|
+
.find(({ candidate }) => candidate.binding.id === binding.id);
|
|
3155
|
+
if (!imported || imported.candidate.imported === '*' || imported.candidate.imported === 'default')
|
|
3156
|
+
return undefined;
|
|
3157
|
+
const targetModule = resolveImportModuleRust(imported.specifier, imported.candidate.imported, context, module);
|
|
3158
|
+
const declaration = targetModule?.declarations.find((candidate) => candidate.kind === 'variable' && 'binding' in candidate && candidate.binding.name === imported.candidate.imported);
|
|
3159
|
+
return declaration?.kind === 'variable' && 'binding' in declaration ? getIrVariableTypeRust(declaration) : undefined;
|
|
3160
|
+
}
|
|
3161
|
+
function getIrVariableTypeRust(variable) {
|
|
3162
|
+
if ('pattern' in variable)
|
|
3163
|
+
return undefined;
|
|
3164
|
+
if (variable.type && variable.type.kind !== 'unknown')
|
|
3165
|
+
return variable.type;
|
|
3166
|
+
const initializer = variable.initializer;
|
|
3167
|
+
if (initializer?.kind !== 'call')
|
|
3168
|
+
return variable.type;
|
|
3169
|
+
const directSymbol = initializer.callee.kind === 'identifier' &&
|
|
3170
|
+
initializer.callee.reference.kind === 'ambient' &&
|
|
3171
|
+
initializer.callee.reference.name === 'Symbol';
|
|
3172
|
+
const symbolMember = initializer.callee.kind === 'property' &&
|
|
3173
|
+
initializer.callee.object.kind === 'identifier' &&
|
|
3174
|
+
initializer.callee.object.reference.kind === 'ambient' &&
|
|
3175
|
+
initializer.callee.object.reference.name === 'Symbol';
|
|
3176
|
+
return directSymbol || symbolMember ? { kind: 'primitive', name: 'symbol' } : variable.type;
|
|
3177
|
+
}
|
|
3178
|
+
function getIrKeyofTypeRustInModule(type, context, module, resolving) {
|
|
3179
|
+
const properties = getIrObjectTypePropertiesRust(type, context, module, resolving);
|
|
3180
|
+
if (!properties)
|
|
3181
|
+
return undefined;
|
|
3182
|
+
const keys = [];
|
|
3183
|
+
if (properties.some((property) => !property.computedKey && !property.phantom)) {
|
|
3184
|
+
keys.push({ kind: 'primitive', name: 'string' });
|
|
3185
|
+
}
|
|
3186
|
+
if (properties.some((property) => property.computedKey && !property.phantom)) {
|
|
3187
|
+
keys.push({ kind: 'primitive', name: 'symbol' });
|
|
3188
|
+
}
|
|
3189
|
+
return createIrClosedTypeUnionRust(keys);
|
|
3190
|
+
}
|
|
3191
|
+
function isIrTypeAssignableForFilterRust(source, target, context, module, resolving) {
|
|
3192
|
+
if (target.kind === 'primitive') {
|
|
3193
|
+
if (source.kind === 'primitive')
|
|
3194
|
+
return source.name === target.name;
|
|
3195
|
+
if (source.kind !== 'literal')
|
|
3196
|
+
return false;
|
|
3197
|
+
return typeof source.value === target.name;
|
|
3198
|
+
}
|
|
3199
|
+
if (target.kind === 'literal')
|
|
3200
|
+
return source.kind === 'literal' && Object.is(source.value, target.value);
|
|
3201
|
+
if (target.kind === 'null' || target.kind === 'undefined')
|
|
3202
|
+
return source.kind === target.kind;
|
|
3203
|
+
const sourceProperties = getIrObjectTypePropertiesRust(source, context, module, resolving);
|
|
3204
|
+
const targetProperties = getIrObjectTypePropertiesRust(target, context, module, resolving);
|
|
3205
|
+
if (!sourceProperties || !targetProperties)
|
|
3206
|
+
return undefined;
|
|
3207
|
+
// Discriminant filters are closed even when the wider structural comparison is indeterminate.
|
|
3208
|
+
// `Extract<Union, { kind: "x" }>` only asks whether each alternative's named literal slot is
|
|
3209
|
+
// compatible; unrelated fields and their host types cannot affect that decision.
|
|
3210
|
+
if (targetProperties.length > 0 && targetProperties.every((property) => property.type.kind === 'literal')) {
|
|
3211
|
+
const decisions = targetProperties.map((targetProperty) => {
|
|
3212
|
+
const sourceProperty = sourceProperties.find((property) => property.name === targetProperty.name);
|
|
3213
|
+
if (!sourceProperty || sourceProperty.optional)
|
|
3214
|
+
return false;
|
|
3215
|
+
const members = getIrClosedTypeMembersRust(sourceProperty.type, context, module, resolving);
|
|
3216
|
+
if (!members)
|
|
3217
|
+
return undefined;
|
|
3218
|
+
return members.every((member) => member.kind === 'literal' &&
|
|
3219
|
+
targetProperty.type.kind === 'literal' &&
|
|
3220
|
+
Object.is(member.value, targetProperty.type.value));
|
|
3221
|
+
});
|
|
3222
|
+
if (decisions.includes(false))
|
|
3223
|
+
return false;
|
|
3224
|
+
if (decisions.every((decision) => decision === true))
|
|
3225
|
+
return true;
|
|
3226
|
+
}
|
|
3227
|
+
const report = analyzeIrTypeStructuralAssignability({ kind: 'object', properties: sourceProperties }, { kind: 'object', properties: targetProperties });
|
|
3228
|
+
return report.status === 'indeterminate' ? undefined : report.status === 'compatible';
|
|
3229
|
+
}
|
|
3230
|
+
function createIrClosedTypeUnionRust(types) {
|
|
3231
|
+
const unique = [...new Map(types.map((type) => [JSON.stringify(type), type])).values()];
|
|
3232
|
+
if (unique.length === 0)
|
|
3233
|
+
return { kind: 'never' };
|
|
3234
|
+
if (unique.length === 1)
|
|
3235
|
+
return unique[0];
|
|
3236
|
+
return { kind: 'union', types: [unique[0], unique[1], ...unique.slice(2)] };
|
|
3237
|
+
}
|
|
3238
|
+
function createIrIntersectionTypeRust(left, right) {
|
|
3239
|
+
const types = [
|
|
3240
|
+
...(left.kind === 'intersection' ? left.types : [left]),
|
|
3241
|
+
...(right.kind === 'intersection' ? right.types : [right]),
|
|
3242
|
+
];
|
|
3243
|
+
return { kind: 'intersection', types: [types[0], types[1], ...types.slice(2)] };
|
|
3244
|
+
}
|
|
3245
|
+
function getIrUnionPrimitiveDomainRust(types, context) {
|
|
3246
|
+
const domains = types.map((type) => getIrTypePrimitiveDomainRust(type, context));
|
|
3247
|
+
const domain = domains[0];
|
|
3248
|
+
return domain !== undefined && domains.every((candidate) => candidate === domain) ? domain : undefined;
|
|
3249
|
+
}
|
|
3250
|
+
function getIrTypePrimitiveDomainRust(type, context, module = context.module, resolving = new Set()) {
|
|
3251
|
+
if (type.kind === 'literal') {
|
|
3252
|
+
const domain = typeof type.value;
|
|
3253
|
+
return domain === 'boolean' || domain === 'number' || domain === 'string' ? domain : undefined;
|
|
3254
|
+
}
|
|
3255
|
+
if (type.kind === 'primitive' && (type.name === 'boolean' || type.name === 'number' || type.name === 'string')) {
|
|
3256
|
+
return type.name;
|
|
3257
|
+
}
|
|
3258
|
+
if (type.kind === 'typeOf') {
|
|
3259
|
+
const resolved = getIrTypeOfValueTypeRust(type, context, module);
|
|
3260
|
+
return resolved ? getIrTypePrimitiveDomainRust(resolved, context, module, resolving) : undefined;
|
|
3261
|
+
}
|
|
3262
|
+
if (type.kind === 'intersection') {
|
|
3263
|
+
const meaningful = type.types.filter((member) => member.kind !== 'object' && getIrObjectTypePropertiesRust(member, context, module, resolving) === undefined);
|
|
3264
|
+
const domains = meaningful.map((member) => getIrTypePrimitiveDomainRust(member, context, module, resolving));
|
|
3265
|
+
const domain = domains[0];
|
|
3266
|
+
return domain !== undefined && domains.every((candidate) => candidate === domain) ? domain : undefined;
|
|
3267
|
+
}
|
|
3268
|
+
if (type.kind !== 'named' ||
|
|
3269
|
+
type.reference.kind !== 'binding' ||
|
|
3270
|
+
type.reference.path.length > 0 ||
|
|
3271
|
+
type.reference.binding.space !== 'type' ||
|
|
3272
|
+
type.reference.binding.kind === 'typeParameter') {
|
|
3273
|
+
return undefined;
|
|
3274
|
+
}
|
|
3275
|
+
const location = getIrNamedTypeDeclarationLocationRust(type.reference.binding, context, module);
|
|
3276
|
+
if (location?.declaration.kind !== 'typeAlias')
|
|
3277
|
+
return undefined;
|
|
3278
|
+
const key = `${location.module.packageName}\0${location.module.source}\0${location.declaration.binding.id}`;
|
|
3279
|
+
if (resolving.has(key))
|
|
3280
|
+
return undefined;
|
|
3281
|
+
try {
|
|
3282
|
+
const plan = createIrTypeParameterSubstitutionPlan(location.declaration.typeParameters, type.typeArguments);
|
|
3283
|
+
const resolved = resolveIrTypeStructuralSubstitution(location.declaration.type, plan);
|
|
3284
|
+
return getIrTypePrimitiveDomainRust(resolved, context, location.module, new Set(resolving).add(key));
|
|
3285
|
+
}
|
|
3286
|
+
catch (error) {
|
|
3287
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3288
|
+
return undefined;
|
|
3289
|
+
throw error;
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
// A union of string literals is how the source language spells a closed set of names, and the source
|
|
3293
|
+
// treats a value of it as a string everywhere: comparing it, returning it, storing it in a string
|
|
3294
|
+
// field. Rust has no implicit conversion, so a unit-variant enum would need a coercion inserted at
|
|
3295
|
+
// every one of those positions — type-directed work this backend does not do yet.
|
|
3296
|
+
//
|
|
3297
|
+
// So the set becomes the string it is made of, and the closed-ness is what is lost. Haxe keeps the
|
|
3298
|
+
// enum because `from String to String` gives it exactly those coercions for free; that the two
|
|
3299
|
+
// targets diverge here is a property of the targets, not an inconsistency in the compiler.
|
|
3300
|
+
function emitStringLiteralUnionRust(declaration, context) {
|
|
3301
|
+
return [
|
|
3302
|
+
`${declaration.exported ? 'pub ' : ''}type ${getBindingTargetNameRust(declaration.binding, context)} = String;`,
|
|
3303
|
+
];
|
|
3304
|
+
}
|
|
3305
|
+
function emitTypeAlias(declaration, context) {
|
|
3306
|
+
if (getIrUnionTypeStringLiteralValues(declaration.type))
|
|
3307
|
+
return emitStringLiteralUnionRust(declaration, context);
|
|
3308
|
+
if (declaration.type.kind === 'union' && getIrUnionTypeMemberRecordsRust(declaration.type, context)) {
|
|
3309
|
+
return emitTaggedUnionRust(getBindingTargetNameRust(declaration.binding, context), declaration.type, declaration.exported, context);
|
|
3310
|
+
}
|
|
3311
|
+
const typeContext = { ...context, activeTypeParameters: declaration.typeParameters };
|
|
3312
|
+
if (declaration.type.kind === 'union' &&
|
|
3313
|
+
!hasIrTypeNullMemberRust(declaration.type) &&
|
|
3314
|
+
!hasIrTypeUndefinedMemberRust(declaration.type) &&
|
|
3315
|
+
!getIrUnionPrimitiveDomainRust(declaration.type.types, typeContext)) {
|
|
3316
|
+
return emitGeneralUnionRust(getBindingTargetNameRust(declaration.binding, context), createGeneralUnionVariantsRust(declaration.type.types, typeContext), declaration.typeParameters, declaration.exported, typeContext);
|
|
3317
|
+
}
|
|
3318
|
+
const recordProperties = isIrTypeRecordMaterializationRust(declaration.type)
|
|
3319
|
+
? getIrObjectTypePropertiesRust(declaration.type, context)
|
|
3320
|
+
: undefined;
|
|
3321
|
+
if (recordProperties) {
|
|
3322
|
+
return emitRecord(getBindingTargetNameRust(declaration.binding, context), recordProperties, declaration.typeParameters, declaration.exported, context);
|
|
3323
|
+
}
|
|
3324
|
+
return [
|
|
3325
|
+
`${declaration.exported ? 'pub ' : ''}type ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeParameters(declaration.typeParameters, context)} = ${emitType(declaration.type, typeContext)};`,
|
|
3326
|
+
];
|
|
3327
|
+
}
|
|
3328
|
+
function isIrTypeRecordMaterializationRust(type) {
|
|
3329
|
+
if (type.kind === 'object' || type.kind === 'intersection')
|
|
3330
|
+
return true;
|
|
3331
|
+
return (type.kind === 'named' &&
|
|
3332
|
+
type.reference.kind === 'ambient' &&
|
|
3333
|
+
['Exclude', 'Extract', 'Omit', 'Partial', 'Pick', 'Required'].includes(type.reference.name));
|
|
3334
|
+
}
|
|
3335
|
+
function emitTupleSpreadExpressionRust(expression, context) {
|
|
3336
|
+
const declarations = [];
|
|
3337
|
+
const elements = [];
|
|
3338
|
+
let resultIndex = 0;
|
|
3339
|
+
for (const segment of expression.segments) {
|
|
3340
|
+
if (segment.kind === 'element') {
|
|
3341
|
+
const target = expression.type.elements[resultIndex];
|
|
3342
|
+
if (!segment.element.expression) {
|
|
3343
|
+
elements.push('None');
|
|
3344
|
+
}
|
|
3345
|
+
else {
|
|
3346
|
+
const name = getGeneratedTargetNameRust('tuple_spread_element', context);
|
|
3347
|
+
declarations.push(`let ${name} = ${emitExpression(segment.element.expression, context)};`);
|
|
3348
|
+
elements.push(target.optional ? `Some(${name})` : name);
|
|
3349
|
+
}
|
|
3350
|
+
resultIndex += 1;
|
|
3351
|
+
continue;
|
|
3352
|
+
}
|
|
3353
|
+
segment.type.elements.forEach((element, offset) => {
|
|
3354
|
+
if (!isIrTypeCloneSafeRust(element.type)) {
|
|
3355
|
+
emissionError(context, `fixed tuple spread source index ${String(offset)} lacks clone-safe Rust ownership evidence`);
|
|
3356
|
+
}
|
|
3357
|
+
});
|
|
3358
|
+
const name = getGeneratedTargetNameRust('tuple_spread_value', context);
|
|
3359
|
+
declarations.push(`let ${name} = &(${emitExpression(segment.expression, context)});`);
|
|
3360
|
+
segment.type.elements.forEach((element, offset) => {
|
|
3361
|
+
const value = `${name}.${String(offset)}.clone()`;
|
|
3362
|
+
const target = expression.type.elements[resultIndex + offset];
|
|
3363
|
+
elements.push(target.optional && !element.optional ? `Some(${value})` : value);
|
|
3364
|
+
});
|
|
3365
|
+
resultIndex += segment.type.elements.length;
|
|
3366
|
+
}
|
|
3367
|
+
const tuple = `(${elements.join(', ')}${elements.length === 1 ? ',' : ''})`;
|
|
3368
|
+
return `({ ${declarations.join(' ')} ${tuple} })`;
|
|
3369
|
+
}
|
|
3370
|
+
function emitTypeArguments(parameters, context) {
|
|
3371
|
+
return parameters.length === 0
|
|
3372
|
+
? ''
|
|
3373
|
+
: `<${parameters.map((parameter) => getBindingTargetNameRust(parameter.binding, context)).join(', ')}>`;
|
|
3374
|
+
}
|
|
3375
|
+
function emitTypeParameters(parameters, context) {
|
|
3376
|
+
if (parameters.length === 0)
|
|
3377
|
+
return '';
|
|
3378
|
+
return `<${parameters
|
|
3379
|
+
.map((parameter) => {
|
|
3380
|
+
const name = getBindingTargetNameRust(parameter.binding, context);
|
|
3381
|
+
// A TypeScript constraint is a value shape, not a Rust trait. Spelling `T extends string` as
|
|
3382
|
+
// `T: String` produces invalid Rust because `String` is a concrete type. Generated records do
|
|
3383
|
+
// clone generic storage, so Clone is the one target capability this declaration can require
|
|
3384
|
+
// without claiming that a source value type is a trait.
|
|
3385
|
+
return `${name}: Clone`;
|
|
3386
|
+
})
|
|
3387
|
+
.join(', ')}>`;
|
|
3388
|
+
}
|
|
3389
|
+
function emitVariable(variable, context) {
|
|
3390
|
+
if ('pattern' in variable)
|
|
3391
|
+
emissionError(context, 'binding patterns require destructuring lowering before Rust emission');
|
|
3392
|
+
const representationType = variable.type?.kind === 'unknown' && variable.initializer
|
|
3393
|
+
? (inferIrExpressionTypeRust(variable.initializer, context) ?? variable.type)
|
|
3394
|
+
: variable.type;
|
|
3395
|
+
if (variable.initialValue === 'undefined') {
|
|
3396
|
+
if (!variable.type || !isNullableType(variable.type)) {
|
|
3397
|
+
emissionError(context, 'observable undefined function-entry value requires a nullable Rust type domain');
|
|
3398
|
+
}
|
|
3399
|
+
const dualSentinelUnion = resolveDualSentinelUnionEnumRust(variable.type, context);
|
|
3400
|
+
const initial = dualSentinelUnion ? `${dualSentinelUnion.name}::Undefined` : 'None';
|
|
3401
|
+
return `let ${variable.mutable ? 'mut ' : ''}${getBindingTargetNameRust(variable.binding, context)}: ${emitType(variable.type, context)} = ${initial};`;
|
|
3402
|
+
}
|
|
3403
|
+
if (context.cellWrappedBindingIds.has(variable.binding.id)) {
|
|
3404
|
+
context.needsCellImport.add('Cell');
|
|
3405
|
+
context.needsRcImport.add('Rc');
|
|
3406
|
+
const name = getBindingTargetNameRust(variable.binding, context);
|
|
3407
|
+
const type = variable.type ? emitType(variable.type, context) : 'f64';
|
|
3408
|
+
const init = variable.initializer ? emitExpression(variable.initializer, context) : '0.0';
|
|
3409
|
+
return `let ${name}: Rc<Cell<${type}>> = Rc::new(Cell::new(${init}));`;
|
|
3410
|
+
}
|
|
3411
|
+
if (context.refCellWrappedBindingIds.has(variable.binding.id)) {
|
|
3412
|
+
context.needsRefCellImport.add('RefCell');
|
|
3413
|
+
context.needsRcImport.add('Rc');
|
|
3414
|
+
const name = getBindingTargetNameRust(variable.binding, context);
|
|
3415
|
+
const type = variable.type ? emitType(variable.type, context) : 'String';
|
|
3416
|
+
const init = variable.initializer ? emitExpression(variable.initializer, context) : 'Default::default()';
|
|
3417
|
+
return `let ${name}: Rc<RefCell<${type}>> = Rc::new(RefCell::new(${init}));`;
|
|
3418
|
+
}
|
|
3419
|
+
if (variable.type && variable.initializer) {
|
|
3420
|
+
const dualSentinelUnion = resolveDualSentinelUnionEnumRust(variable.type, context);
|
|
3421
|
+
if (dualSentinelUnion) {
|
|
3422
|
+
const wrapped = emitDualSentinelUnionConstructionRust(variable.initializer, dualSentinelUnion, context);
|
|
3423
|
+
if (wrapped) {
|
|
3424
|
+
const mutable = variable.mutable ||
|
|
3425
|
+
(context.referentMutatedBindingIds.has(variable.binding.id) && !isIrTypeTypedArrayRust(variable.type));
|
|
3426
|
+
return `let ${mutable ? 'mut ' : ''}${getBindingTargetNameRust(variable.binding, context)}: ${emitType(variable.type, context)} = ${wrapped};`;
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
const targetEnum = resolvePrimitiveUnionEnumRust(variable.type, context);
|
|
3430
|
+
if (targetEnum) {
|
|
3431
|
+
const wrapped = emitPrimitiveUnionConstructionRust(variable.initializer, targetEnum, context);
|
|
3432
|
+
if (wrapped) {
|
|
3433
|
+
const deferred = !variable.initializer && context.deferredBindingIds.has(variable.binding.id);
|
|
3434
|
+
const mutable = (variable.mutable && !deferred) ||
|
|
3435
|
+
(context.referentMutatedBindingIds.has(variable.binding.id) && !isIrTypeTypedArrayRust(variable.type));
|
|
3436
|
+
return `let ${mutable ? 'mut ' : ''}${getBindingTargetNameRust(variable.binding, context)}: ${emitType(variable.type, context)} = ${wrapped};`;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
const isArrayElementBinding = 'binding' in variable && context.arrayElementBindingIds.has(variable.binding.id);
|
|
3441
|
+
const type = representationType && !(variable.initializer?.kind === 'objectRest' && representationType.kind === 'object')
|
|
3442
|
+
? `: ${isArrayElementBinding ? `Option<${emitType(representationType, context)}>` : emitType(representationType, context)}`
|
|
3443
|
+
: '';
|
|
3444
|
+
const isCallbackInitializer = variable.type?.kind === 'function' && variable.initializer?.kind === 'function';
|
|
3445
|
+
if (isCallbackInitializer)
|
|
3446
|
+
context.needsRcImport.add('Rc');
|
|
3447
|
+
const isNullableArrayElement = 'binding' in variable &&
|
|
3448
|
+
(context.nullableBindingIds.has(variable.binding.id) || isArrayElementBinding) &&
|
|
3449
|
+
variable.initializer?.kind === 'element' &&
|
|
3450
|
+
!variable.initializer.optional &&
|
|
3451
|
+
variable.initializer.semantics.receivers.includes('array');
|
|
3452
|
+
const initializer = variable.initializer
|
|
3453
|
+
? ` = ${normalizeSourceTextGrouping(isCallbackInitializer ? emitClosureWithCellClonesRust(variable.initializer, context) : isNullableArrayElement ? emitOptionShapedOperandRust(variable.initializer, context) : emitOwnedOperandRust(variable.initializer, context))}`
|
|
3454
|
+
: '';
|
|
3455
|
+
// A binding declared without a value and written once afterwards is Rust's deferred
|
|
3456
|
+
// initialization, not a mutation: the source hoisted the declaration above the assignment, and
|
|
3457
|
+
// `mut` on it would claim a rebinding that never happens.
|
|
3458
|
+
const deferred = !variable.initializer && context.deferredBindingIds.has(variable.binding.id);
|
|
3459
|
+
// Rust asks for `mut` to reach a value's own fields through a method, where the source language
|
|
3460
|
+
// only asks for it to rebind the name. A `const` the source mutates through is still `mut` here.
|
|
3461
|
+
const mutable = (variable.mutable && !deferred) ||
|
|
3462
|
+
(context.referentMutatedBindingIds.has(variable.binding.id) && !isIrTypeTypedArrayRust(variable.type));
|
|
3463
|
+
return `let ${mutable ? 'mut ' : ''}${getBindingTargetNameRust(variable.binding, context)}${type}${initializer};`;
|
|
3464
|
+
}
|
|
3465
|
+
function emitVariableDeclaration(declaration, context) {
|
|
3466
|
+
if ('pattern' in declaration)
|
|
3467
|
+
emissionError(context, 'binding patterns require destructuring lowering before Rust emission');
|
|
3468
|
+
if (!declaration.initializer || !declaration.type) {
|
|
3469
|
+
emissionError(context, `module variable ${declaration.binding.name} requires an initializer and type`);
|
|
3470
|
+
}
|
|
3471
|
+
if (declaration.mutable)
|
|
3472
|
+
emissionError(context, `mutable module variable ${declaration.binding.name} requires synchronization lowering`);
|
|
3473
|
+
return [
|
|
3474
|
+
`${declaration.exported ? 'pub ' : ''}const ${getBindingTargetNameRust(declaration.binding, context)}: ${emitType(declaration.type, context)} = ${emitExpression(declaration.initializer, context)};`,
|
|
3475
|
+
];
|
|
3476
|
+
}
|
|
3477
|
+
function getBindingTargetNameRust(binding, context) {
|
|
3478
|
+
const targetName = context.targetNames.get(binding.id);
|
|
3479
|
+
if (!targetName)
|
|
3480
|
+
emissionError(context, `binding ${binding.name} has no Rust target name allocation`);
|
|
3481
|
+
return targetName;
|
|
3482
|
+
}
|
|
3483
|
+
function getGeneratedTargetNameRust(preferredName, context) {
|
|
3484
|
+
let name = preferredName;
|
|
3485
|
+
const separator = /^[A-Z]/u.test(preferredName) ? '' : '_';
|
|
3486
|
+
for (let suffix = 2; context.generatedNames.has(name); suffix += 1) {
|
|
3487
|
+
name = `${preferredName}${separator}${String(suffix)}`;
|
|
3488
|
+
}
|
|
3489
|
+
context.generatedNames.add(name);
|
|
3490
|
+
return name;
|
|
3491
|
+
}
|
|
3492
|
+
function getElementAccessTupleIndexRust(expression, context) {
|
|
3493
|
+
if (expression.semantics.receivers.length !== 1 ||
|
|
3494
|
+
expression.index.kind !== 'literal' ||
|
|
3495
|
+
typeof expression.index.value !== 'number' ||
|
|
3496
|
+
!Number.isSafeInteger(expression.index.value) ||
|
|
3497
|
+
expression.index.value < 0) {
|
|
3498
|
+
emissionError(context, 'tuple projection requires one statically known nonnegative integer index');
|
|
3499
|
+
}
|
|
3500
|
+
return expression.index.value;
|
|
3501
|
+
}
|
|
3502
|
+
function getPreferredBindingNameRust(binding, constants) {
|
|
3503
|
+
if (constants.has(binding.id))
|
|
3504
|
+
return screamingSnakeCase(binding.name);
|
|
3505
|
+
return binding.space === 'type' ||
|
|
3506
|
+
binding.kind === 'class' ||
|
|
3507
|
+
binding.kind === 'enum' ||
|
|
3508
|
+
(binding.kind === 'import' && /^[A-Z]/u.test(binding.name))
|
|
3509
|
+
? safeRustTypeName(binding.name)
|
|
3510
|
+
: safeRustValueName(binding.name);
|
|
3511
|
+
}
|
|
3512
|
+
function getTypeReferenceTargetNameRust(type, context) {
|
|
3513
|
+
if (type.reference.kind === 'ambient') {
|
|
3514
|
+
const targetName = getCompilerRuntimeExternalSymbolTargetRust(type.reference.name, 'type', context.options.hostBindings);
|
|
3515
|
+
if (!targetName)
|
|
3516
|
+
emissionError(context, `external type ${type.reference.name} has no Rust binding`);
|
|
3517
|
+
return isCompilerRuntimeExternalSymbolProvidedRust(type.reference.name, 'type', context.options.hostBindings)
|
|
3518
|
+
? recordRuntimeTypeRust(targetName, context)
|
|
3519
|
+
: targetName;
|
|
3520
|
+
}
|
|
3521
|
+
return [
|
|
3522
|
+
getTypeBindingTargetNameRust(type.reference.binding, context),
|
|
3523
|
+
...type.reference.path.map(safeRustTypeName),
|
|
3524
|
+
].join('::');
|
|
3525
|
+
}
|
|
3526
|
+
function getTypeBindingTargetNameRust(binding, context) {
|
|
3527
|
+
const allocated = context.targetNames.get(binding.id);
|
|
3528
|
+
if (allocated)
|
|
3529
|
+
return allocated;
|
|
3530
|
+
for (const module of context.sourceModules) {
|
|
3531
|
+
const declaration = module.declarations.find((candidate) => 'binding' in candidate && candidate.binding.id === binding.id);
|
|
3532
|
+
if (declaration && 'binding' in declaration) {
|
|
3533
|
+
return getRustQualifiedTypeName(module, declaration.binding.name, context);
|
|
3534
|
+
}
|
|
3535
|
+
const imported = module.imports
|
|
3536
|
+
.flatMap((item) => item.bindings.map((candidate) => ({ candidate, specifier: item.specifier })))
|
|
3537
|
+
.find(({ candidate }) => candidate.binding.id === binding.id);
|
|
3538
|
+
if (!imported || imported.candidate.imported === '*' || imported.candidate.imported === 'default')
|
|
3539
|
+
continue;
|
|
3540
|
+
const target = resolveImportModuleRust(imported.specifier, imported.candidate.imported, context, module);
|
|
3541
|
+
if (target)
|
|
3542
|
+
return getRustQualifiedTypeName(target, imported.candidate.imported, context);
|
|
3543
|
+
}
|
|
3544
|
+
emissionError(context, `binding ${binding.name} has no Rust type target resolution`);
|
|
3545
|
+
}
|
|
3546
|
+
function getRustQualifiedTypeName(module, name, context) {
|
|
3547
|
+
const targetName = safeRustTypeName(name);
|
|
3548
|
+
if (module.packageName === context.module.packageName) {
|
|
3549
|
+
return `crate::${getRustModuleName(module)}::${targetName}`;
|
|
3550
|
+
}
|
|
3551
|
+
return `${convertPackageNameToRustCrateName(module.packageName).replaceAll('-', '_')}::${targetName}`;
|
|
3552
|
+
}
|
|
3553
|
+
function assertStructuralObjectCompatibilityRust(module, modules, resolution) {
|
|
3554
|
+
const diagnostics = analyzeIrModuleStructuralObjectCompatibilityAcrossModules(module, modules, resolution).diagnostics;
|
|
3555
|
+
const diagnostic = diagnostics.find((candidate) => candidate.disposition !== 'indeterminate') ??
|
|
3556
|
+
diagnostics.find((candidate) => candidate.code !== 'unresolved-named-construction-target');
|
|
3557
|
+
if (diagnostic) {
|
|
3558
|
+
throw createBackendEmissionFailure('rust', module, `structural object compatibility ${diagnostic.code} at ${JSON.stringify(diagnostic.path)}: ${diagnostic.message}`);
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
function replaceIrModuleBackendContext(modules, replacement) {
|
|
3562
|
+
return modules.map((module) => module.packageName === replacement.packageName &&
|
|
3563
|
+
module.source === replacement.source &&
|
|
3564
|
+
module.name === replacement.name
|
|
3565
|
+
? replacement
|
|
3566
|
+
: module);
|
|
3567
|
+
}
|
|
3568
|
+
function assertRuntimeExternalSymbolBindingsRust(module, options) {
|
|
3569
|
+
const completeness = analyzeCompilerRuntimeExternalSymbolCompleteness(collectIrModulesRuntimeExternalSymbolIdentities([module]), createCompilerRuntimeExternalSymbolBindingPlanRust(options.hostBindings));
|
|
3570
|
+
if (completeness.kind === 'complete')
|
|
3571
|
+
return;
|
|
3572
|
+
const problems = [
|
|
3573
|
+
completeness.missingExternalSymbols.length > 0
|
|
3574
|
+
? `missing: ${completeness.missingExternalSymbols.map(formatRuntimeExternalSymbolIdentity).join(', ')}`
|
|
3575
|
+
: undefined,
|
|
3576
|
+
completeness.duplicateExternalSymbols.length > 0
|
|
3577
|
+
? `duplicate: ${completeness.duplicateExternalSymbols.map(formatRuntimeExternalSymbolIdentity).join(', ')}`
|
|
3578
|
+
: undefined,
|
|
3579
|
+
].filter((problem) => problem !== undefined);
|
|
3580
|
+
throw createBackendEmissionFailure('rust', module, `runtime external symbol binding plan is incomplete (${problems.join('; ')})`, 'rust-runtime-external-symbol-binding-incomplete', { classification: 'target-runtime' });
|
|
3581
|
+
}
|
|
3582
|
+
function assertRuntimeExternalConstructorAbiRust(module) {
|
|
3583
|
+
const completeness = analyzeCompilerRuntimeExternalConstructorAbiCompleteness(collectIrModulesRuntimeExternalConstructorInvocations([module]), createCompilerRuntimeExternalConstructorAbiPlanRust());
|
|
3584
|
+
if (completeness.kind === 'complete')
|
|
3585
|
+
return;
|
|
3586
|
+
const problems = [
|
|
3587
|
+
completeness.missingExternalConstructors.length > 0
|
|
3588
|
+
? `missing: ${completeness.missingExternalConstructors.map(formatRuntimeExternalConstructorInvocation).join(', ')}`
|
|
3589
|
+
: undefined,
|
|
3590
|
+
completeness.duplicateExternalConstructors.length > 0
|
|
3591
|
+
? `duplicate: ${completeness.duplicateExternalConstructors.map(formatRuntimeExternalSymbolIdentity).join(', ')}`
|
|
3592
|
+
: undefined,
|
|
3593
|
+
completeness.invalidExternalConstructors.length > 0
|
|
3594
|
+
? `invalid: ${completeness.invalidExternalConstructors.map(formatRuntimeExternalSymbolIdentity).join(', ')}`
|
|
3595
|
+
: undefined,
|
|
3596
|
+
].filter((problem) => problem !== undefined);
|
|
3597
|
+
throw createBackendEmissionFailure('rust', module, `runtime external constructor ABI plan is incomplete (${problems.join('; ')})`, 'rust-runtime-external-constructor-abi-incomplete', { classification: 'target-runtime' });
|
|
3598
|
+
}
|
|
3599
|
+
function formatRuntimeExternalConstructorInvocation(invocation) {
|
|
3600
|
+
return `${formatRuntimeExternalSymbolIdentity(invocation.externalSymbol)}(${invocation.providedArgumentCount === 'dynamic' ? '...' : String(invocation.providedArgumentCount)})`;
|
|
3601
|
+
}
|
|
3602
|
+
function formatRuntimeExternalSymbolIdentity(identity) {
|
|
3603
|
+
return `${identity.sourceName}[${identity.space}]`;
|
|
3604
|
+
}
|
|
3605
|
+
function isAmbientIdentifier(expression) {
|
|
3606
|
+
return expression.kind === 'identifier' && expression.reference.kind === 'ambient';
|
|
3607
|
+
}
|
|
3608
|
+
function emissionError(context, message) {
|
|
3609
|
+
throw createBackendEmissionFailure('rust', context.module, message);
|
|
3610
|
+
}
|
|
3611
|
+
function collectStringConcatenationOperands(expression) {
|
|
3612
|
+
if (expression.kind === 'binary' &&
|
|
3613
|
+
expression.operator === '+' &&
|
|
3614
|
+
expression.semantics.left.flow === 'string' &&
|
|
3615
|
+
expression.semantics.right.flow === 'string') {
|
|
3616
|
+
return [
|
|
3617
|
+
...collectStringConcatenationOperands(expression.left),
|
|
3618
|
+
...collectStringConcatenationOperands(expression.right),
|
|
3619
|
+
];
|
|
3620
|
+
}
|
|
3621
|
+
return [expression];
|
|
3622
|
+
}
|
|
3623
|
+
function emitStringConcatenationRust(expression, context) {
|
|
3624
|
+
const operands = collectStringConcatenationOperands(expression);
|
|
3625
|
+
const format = operands
|
|
3626
|
+
.map((operand) => operand.kind === 'literal' && typeof operand.value === 'string'
|
|
3627
|
+
? operand.value.replaceAll('{', '{{').replaceAll('}', '}}')
|
|
3628
|
+
: '{}')
|
|
3629
|
+
.join('');
|
|
3630
|
+
const values = operands.flatMap((operand) => operand.kind === 'literal' && typeof operand.value === 'string' ? [] : [emitExpression(operand, context)]);
|
|
3631
|
+
return `format!(${JSON.stringify(format)}${values.length > 0 ? `, ${values.join(', ')}` : ''})`;
|
|
3632
|
+
}
|
|
3633
|
+
function emitAssignmentOperatorRust(operator, semantics, context) {
|
|
3634
|
+
const emitted = rustAssignmentOperatorEmission[operator];
|
|
3635
|
+
if (!emitted)
|
|
3636
|
+
emissionError(context, `operator ${operator} requires Rust semantic lowering`);
|
|
3637
|
+
if (!isAssignmentOperatorDirectRust(operator, semantics)) {
|
|
3638
|
+
emissionError(context, `operator ${operator} on ${semantics.left.flow} and ${semantics.right.flow} requires Rust type-directed lowering`);
|
|
3639
|
+
}
|
|
3640
|
+
return emitted;
|
|
3641
|
+
}
|
|
3642
|
+
function emitBinaryOperatorRust(operator, semantics, context) {
|
|
3643
|
+
const emitted = rustBinaryOperatorEmission[operator];
|
|
3644
|
+
if (!emitted)
|
|
3645
|
+
emissionError(context, `operator ${operator} requires Rust semantic lowering`);
|
|
3646
|
+
if (!isBinaryOperatorDirectRust(operator, semantics)) {
|
|
3647
|
+
emissionError(context, `operator ${operator} on ${semantics.left.flow} and ${semantics.right.flow} requires Rust type-directed lowering`);
|
|
3648
|
+
}
|
|
3649
|
+
return emitted;
|
|
3650
|
+
}
|
|
3651
|
+
function getStaticTypeofNameRust(domain) {
|
|
3652
|
+
switch (domain) {
|
|
3653
|
+
case 'bigint':
|
|
3654
|
+
case 'boolean':
|
|
3655
|
+
case 'number':
|
|
3656
|
+
case 'string':
|
|
3657
|
+
case 'symbol':
|
|
3658
|
+
case 'undefined':
|
|
3659
|
+
return domain;
|
|
3660
|
+
case 'null':
|
|
3661
|
+
case 'object':
|
|
3662
|
+
case 'unknown':
|
|
3663
|
+
return undefined;
|
|
3664
|
+
}
|
|
3665
|
+
return undefined;
|
|
3666
|
+
}
|
|
3667
|
+
function emitNumericUpdateUnaryRust(expression, context) {
|
|
3668
|
+
const bindingType = expression.operand.kind === 'identifier' && expression.operand.reference.kind === 'binding'
|
|
3669
|
+
? context.bindingTypes.get(expression.operand.reference.binding.id)
|
|
3670
|
+
: undefined;
|
|
3671
|
+
if (expression.semantics.operand.flow !== 'number' ||
|
|
3672
|
+
expression.semantics.result !== 'number' ||
|
|
3673
|
+
expression.operand.kind !== 'identifier' ||
|
|
3674
|
+
expression.operand.reference.kind !== 'binding' ||
|
|
3675
|
+
bindingType?.kind !== 'primitive' ||
|
|
3676
|
+
bindingType.name !== 'number') {
|
|
3677
|
+
emissionError(context, `operator ${expression.operator} requires a numeric Rust binding target`);
|
|
3678
|
+
}
|
|
3679
|
+
const name = emitIdentifierReferenceRust(expression.operand.reference, context);
|
|
3680
|
+
const arithmetic = expression.operator === '++' ? '+' : '-';
|
|
3681
|
+
if (context.cellWrappedBindingIds.has(expression.operand.reference.binding.id)) {
|
|
3682
|
+
const previous = getGeneratedTargetNameRust('update_previous', context);
|
|
3683
|
+
const updated = `${previous} ${arithmetic} 1.0`;
|
|
3684
|
+
return expression.postfix
|
|
3685
|
+
? `{ let ${previous} = ${name}.get(); ${name}.set(${updated}); ${previous} }`
|
|
3686
|
+
: `{ let ${previous} = ${name}.get(); ${name}.set(${updated}); ${name}.get() }`;
|
|
3687
|
+
}
|
|
3688
|
+
if (context.refCellWrappedBindingIds.has(expression.operand.reference.binding.id)) {
|
|
3689
|
+
emissionError(context, `operator ${expression.operator} cannot update a non-Copy Rust binding`);
|
|
3690
|
+
}
|
|
3691
|
+
if (!expression.postfix)
|
|
3692
|
+
return `{ ${name} ${arithmetic}= 1.0; ${name} }`;
|
|
3693
|
+
const previous = getGeneratedTargetNameRust('update_previous', context);
|
|
3694
|
+
return `{ let ${previous} = ${name}; ${name} ${arithmetic}= 1.0; ${previous} }`;
|
|
3695
|
+
}
|
|
3696
|
+
function emitPrefixUnaryOperatorRust(operator, semantics, context) {
|
|
3697
|
+
const decision = rustPrefixUnaryOperatorDecision[operator];
|
|
3698
|
+
if ('refusal' in decision)
|
|
3699
|
+
emissionError(context, decision.refusal);
|
|
3700
|
+
if (!isPrefixUnaryOperatorDirectRust(operator, semantics)) {
|
|
3701
|
+
emissionError(context, `operator ${operator} on ${semantics.operand.flow} requires Rust type-directed lowering`);
|
|
3702
|
+
}
|
|
3703
|
+
return decision.emitted;
|
|
3704
|
+
}
|
|
3705
|
+
function isAssignmentOperatorDirectRust(operator, semantics) {
|
|
3706
|
+
if (operator === '=')
|
|
3707
|
+
return true;
|
|
3708
|
+
if (operator === '%=' || operator === '*=' || operator === '+=' || operator === '-=' || operator === '/=') {
|
|
3709
|
+
return hasMatchingOperatorDomains(semantics, ['number']);
|
|
3710
|
+
}
|
|
3711
|
+
return false;
|
|
3712
|
+
}
|
|
3713
|
+
// Which expressions the Rust emitter renders as an `Option`. An optional chain projects into one; an
|
|
3714
|
+
// ordinary value does not, and wrapping it would claim a nullability the emitted type does not have.
|
|
3715
|
+
function isIrExpressionOptionShapedRust(expression, context) {
|
|
3716
|
+
// An optional member is an `Option` field in the emitted record, so reading it is already the shape
|
|
3717
|
+
// the operator needs — the chain is about the object being absent, this is about the member.
|
|
3718
|
+
//
|
|
3719
|
+
// A chain the source wrote over a receiver its own types say cannot be absent produces a plain
|
|
3720
|
+
// value, not an `Option`. The `?.` is redundant there, and treating it as an `Option` asks a value
|
|
3721
|
+
// for a method it does not have.
|
|
3722
|
+
if (expression.kind === 'property') {
|
|
3723
|
+
if (expression.optionalChain?.receiverNullish === 'excluded')
|
|
3724
|
+
return false;
|
|
3725
|
+
return expression.optional || expression.absent === 'optionalMember';
|
|
3726
|
+
}
|
|
3727
|
+
if (expression.kind === 'call')
|
|
3728
|
+
return expression.optional;
|
|
3729
|
+
// An array index is absent-admitting in the source language whatever the index is, which is why
|
|
3730
|
+
// `values[index] ?? fallback` is ordinary code. Rust's `[]` panics instead, so the coalesce reads
|
|
3731
|
+
// through `get`, which is both the Option the operator needs and the faithful behaviour.
|
|
3732
|
+
if (expression.kind === 'element') {
|
|
3733
|
+
return expression.optional || (expression.semantics.receivers.includes('array') && !expression.optional);
|
|
3734
|
+
}
|
|
3735
|
+
if (expression.kind === 'identifier' &&
|
|
3736
|
+
expression.reference.kind === 'binding' &&
|
|
3737
|
+
(context.nullableBindingIds.has(expression.reference.binding.id) ||
|
|
3738
|
+
context.arrayElementBindingIds.has(expression.reference.binding.id)))
|
|
3739
|
+
return true;
|
|
3740
|
+
return expression.kind === 'undefinedDefault';
|
|
3741
|
+
}
|
|
3742
|
+
function emitOptionShapedOperandRust(expression, context) {
|
|
3743
|
+
if (expression.kind === 'element' && !expression.optional && expression.semantics.receivers.includes('array')) {
|
|
3744
|
+
return `${emitExpression(expression.object, context)}.get(${emitIndexOperandRust(expression.index, context)}).cloned()`;
|
|
3745
|
+
}
|
|
3746
|
+
return emitExpression(expression, context);
|
|
3747
|
+
}
|
|
3748
|
+
function isBinaryOperatorDirectRust(operator, semantics) {
|
|
3749
|
+
if (operator === '%' || operator === '*' || operator === '+' || operator === '-' || operator === '/') {
|
|
3750
|
+
return hasMatchingOperatorDomains(semantics, ['number']);
|
|
3751
|
+
}
|
|
3752
|
+
if (operator === '<' || operator === '<=' || operator === '>' || operator === '>=') {
|
|
3753
|
+
return semantics.left.flow === 'number' && semantics.right.flow === 'number' && semantics.result === 'boolean';
|
|
3754
|
+
}
|
|
3755
|
+
if (operator === '&&' || operator === '||') {
|
|
3756
|
+
return hasMatchingOperatorDomains(semantics, ['boolean']);
|
|
3757
|
+
}
|
|
3758
|
+
if (operator === '===' || operator === '!==') {
|
|
3759
|
+
return (semantics.left.flow === semantics.right.flow &&
|
|
3760
|
+
semantics.result === 'boolean' &&
|
|
3761
|
+
(semantics.left.flow === 'boolean' || semantics.left.flow === 'number' || semantics.left.flow === 'string'));
|
|
3762
|
+
}
|
|
3763
|
+
if (operator === '&' || operator === '|' || operator === '^' || operator === '<<' || operator === '>>') {
|
|
3764
|
+
return hasMatchingOperatorDomains(semantics, ['number']);
|
|
3765
|
+
}
|
|
3766
|
+
return false;
|
|
3767
|
+
}
|
|
3768
|
+
function isPrefixUnaryOperatorDirectRust(operator, semantics) {
|
|
3769
|
+
if (operator === '!')
|
|
3770
|
+
return semantics.operand.flow === 'boolean' && semantics.result === 'boolean';
|
|
3771
|
+
if (operator === '+' || operator === '-')
|
|
3772
|
+
return semantics.operand.flow === 'number' && semantics.result === 'number';
|
|
3773
|
+
if (operator === '~')
|
|
3774
|
+
return semantics.operand.flow === 'number' && semantics.result === 'number';
|
|
3775
|
+
return false;
|
|
3776
|
+
}
|
|
3777
|
+
function hasMatchingOperatorDomains(semantics, supported) {
|
|
3778
|
+
return (semantics.left.flow === semantics.right.flow &&
|
|
3779
|
+
semantics.left.flow === semantics.result &&
|
|
3780
|
+
supported.includes(semantics.left.flow));
|
|
3781
|
+
}
|
|
3782
|
+
function isNullableType(type) {
|
|
3783
|
+
return (type.kind === 'null' ||
|
|
3784
|
+
type.kind === 'undefined' ||
|
|
3785
|
+
(type.kind === 'union' && type.types.some((member) => member.kind === 'null' || member.kind === 'undefined')));
|
|
3786
|
+
}
|
|
3787
|
+
function hasIrTypeNullMemberRust(type) {
|
|
3788
|
+
return type.kind === 'null' || (type.kind === 'union' && type.types.some((member) => member.kind === 'null'));
|
|
3789
|
+
}
|
|
3790
|
+
function hasIrTypeUndefinedMemberRust(type) {
|
|
3791
|
+
return (type.kind === 'undefined' || (type.kind === 'union' && type.types.some((member) => member.kind === 'undefined')));
|
|
3792
|
+
}
|
|
3793
|
+
function isIrTypeCloneSafeRust(type) {
|
|
3794
|
+
switch (type.kind) {
|
|
3795
|
+
case 'array':
|
|
3796
|
+
return isIrTypeCloneSafeRust(type.element);
|
|
3797
|
+
case 'literal':
|
|
3798
|
+
case 'never':
|
|
3799
|
+
case 'null':
|
|
3800
|
+
case 'primitive':
|
|
3801
|
+
case 'undefined':
|
|
3802
|
+
return true;
|
|
3803
|
+
case 'tuple':
|
|
3804
|
+
return type.elements.every((element) => isIrTypeCloneSafeRust(element.type));
|
|
3805
|
+
case 'union':
|
|
3806
|
+
return type.types.every(isIrTypeCloneSafeRust);
|
|
3807
|
+
case 'function':
|
|
3808
|
+
case 'conditionalFacet':
|
|
3809
|
+
case 'indexedAccess':
|
|
3810
|
+
case 'intersection':
|
|
3811
|
+
case 'keyof':
|
|
3812
|
+
case 'named':
|
|
3813
|
+
case 'object':
|
|
3814
|
+
case 'typeOf':
|
|
3815
|
+
case 'unknown':
|
|
3816
|
+
return false;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
// `Rc<dyn Fn>` is cloneable but the callable trait object does not implement `Debug`. Deriving
|
|
3820
|
+
// `Debug` for a record that contains one directly, through a container, or through a resolved source
|
|
3821
|
+
// type therefore makes otherwise valid generated Rust fail to compile. Retain the useful derive for
|
|
3822
|
+
// every record where no callable is proven, and omit only the unsupported bound.
|
|
3823
|
+
function emitRustRecordDerive(types, context) {
|
|
3824
|
+
return types.some((type) => containsIrFunctionTypeRust(type, context))
|
|
3825
|
+
? '#[derive(Clone)]'
|
|
3826
|
+
: '#[derive(Clone, Debug)]';
|
|
3827
|
+
}
|
|
3828
|
+
function containsIrFunctionTypeRust(type, context, module = context.module, resolving = new Set()) {
|
|
3829
|
+
switch (type.kind) {
|
|
3830
|
+
case 'function':
|
|
3831
|
+
return true;
|
|
3832
|
+
case 'array':
|
|
3833
|
+
return containsIrFunctionTypeRust(type.element, context, module, resolving);
|
|
3834
|
+
case 'tuple':
|
|
3835
|
+
return type.elements.some((element) => containsIrFunctionTypeRust(element.type, context, module, resolving));
|
|
3836
|
+
case 'intersection':
|
|
3837
|
+
case 'union':
|
|
3838
|
+
return type.types.some((member) => containsIrFunctionTypeRust(member, context, module, resolving));
|
|
3839
|
+
case 'object':
|
|
3840
|
+
return type.properties.some((property) => containsIrFunctionTypeRust(property.type, context, module, resolving));
|
|
3841
|
+
case 'named': {
|
|
3842
|
+
if (type.typeArguments.some((argument) => containsIrFunctionTypeRust(argument, context, module, resolving))) {
|
|
3843
|
+
return true;
|
|
3844
|
+
}
|
|
3845
|
+
if (type.reference.kind !== 'binding' ||
|
|
3846
|
+
type.reference.path.length > 0 ||
|
|
3847
|
+
type.reference.binding.space !== 'type' ||
|
|
3848
|
+
type.reference.binding.kind === 'typeParameter') {
|
|
3849
|
+
return false;
|
|
3850
|
+
}
|
|
3851
|
+
const binding = type.reference.binding;
|
|
3852
|
+
const location = getIrNamedTypeDeclarationLocationRust(binding, context, module);
|
|
3853
|
+
if (location) {
|
|
3854
|
+
const key = `${location.module.packageName}\0${location.module.source}\0${location.declaration.binding.id}`;
|
|
3855
|
+
if (resolving.has(key))
|
|
3856
|
+
return false;
|
|
3857
|
+
const active = new Set(resolving).add(key);
|
|
3858
|
+
if (location.declaration.kind === 'typeAlias') {
|
|
3859
|
+
try {
|
|
3860
|
+
const plan = createIrTypeParameterSubstitutionPlan(location.declaration.typeParameters, type.typeArguments);
|
|
3861
|
+
return containsIrFunctionTypeRust(resolveIrTypeStructuralSubstitution(location.declaration.type, plan), context, location.module, active);
|
|
3862
|
+
}
|
|
3863
|
+
catch (error) {
|
|
3864
|
+
if (isCompilerStructuralTypeSubstitutionFailure(error))
|
|
3865
|
+
return false;
|
|
3866
|
+
throw error;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
const properties = getIrObjectTypePropertiesRust(type, context, module, resolving);
|
|
3870
|
+
return (properties?.some((property) => containsIrFunctionTypeRust(property.type, context, location.module, active)) ??
|
|
3871
|
+
false);
|
|
3872
|
+
}
|
|
3873
|
+
const classDeclaration = [module, ...context.sourceModules]
|
|
3874
|
+
.flatMap((candidate) => candidate.declarations)
|
|
3875
|
+
.find((candidate) => candidate.kind === 'class' && candidate.binding.id === binding.id);
|
|
3876
|
+
if (classDeclaration?.kind !== 'class')
|
|
3877
|
+
return false;
|
|
3878
|
+
const key = `${module.packageName}\0${module.source}\0${classDeclaration.binding.id}`;
|
|
3879
|
+
if (resolving.has(key))
|
|
3880
|
+
return false;
|
|
3881
|
+
const active = new Set(resolving).add(key);
|
|
3882
|
+
return (classDeclaration.fields.some((field) => containsIrFunctionTypeRust(field.type, context, module, active)) ||
|
|
3883
|
+
(classDeclaration.extends
|
|
3884
|
+
? containsIrFunctionTypeRust(classDeclaration.extends, context, module, active)
|
|
3885
|
+
: false));
|
|
3886
|
+
}
|
|
3887
|
+
case 'conditionalFacet':
|
|
3888
|
+
case 'indexedAccess':
|
|
3889
|
+
case 'keyof':
|
|
3890
|
+
case 'literal':
|
|
3891
|
+
case 'never':
|
|
3892
|
+
case 'null':
|
|
3893
|
+
case 'primitive':
|
|
3894
|
+
case 'typeOf':
|
|
3895
|
+
case 'undefined':
|
|
3896
|
+
case 'unknown':
|
|
3897
|
+
return false;
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
function opaqueHostType(context) {
|
|
3901
|
+
return context.options.opaqueHostType ?? recordRuntimeTypeRust('OpaqueHostValue', context);
|
|
3902
|
+
}
|
|
3903
|
+
function rustImportModule(specifier, context) {
|
|
3904
|
+
if (specifier.startsWith('.')) {
|
|
3905
|
+
const resolvedModule = resolveImportModuleRust(specifier, undefined, context);
|
|
3906
|
+
if (resolvedModule)
|
|
3907
|
+
return `crate::${getRustModuleName(resolvedModule)}`;
|
|
3908
|
+
const target = path.posix.normalize(path.posix.join(path.posix.dirname(context.module.source), specifier.replace(/\.[cm]?js$/u, '.ts')));
|
|
3909
|
+
const resolved = /\.tsx?$/u.test(target) ? target : `${target}.ts`;
|
|
3910
|
+
return `crate::${convertSourcePathToRustModuleName(resolved) ?? `_internal_${snakeCase(path.posix.basename(target))}`}`;
|
|
3911
|
+
}
|
|
3912
|
+
if (specifier.startsWith('@')) {
|
|
3913
|
+
const packageName = /^(@[^/]+\/[^/]+)/u.exec(specifier)?.[1];
|
|
3914
|
+
if (!packageName)
|
|
3915
|
+
emissionError(context, `cannot identify package import ${specifier}`);
|
|
3916
|
+
return convertPackageNameToRustCrateName(packageName).replaceAll('-', '_');
|
|
3917
|
+
}
|
|
3918
|
+
emissionError(context, `external import ${specifier} requires a runtime or standard-library mapping`);
|
|
3919
|
+
}
|
|
3920
|
+
function resolveImportModuleRust(specifier, importedName, context, importer = context.module) {
|
|
3921
|
+
const matching = context.moduleResolution?.edges.filter((edge) => edge.specifier === specifier) ?? [];
|
|
3922
|
+
const exact = matching.filter((edge) => edge.importer && isRustCompilerModuleIdentityEqual(edge.importer, importer));
|
|
3923
|
+
const scoped = exact.length > 0 ? exact : matching.filter((edge) => !edge.importer);
|
|
3924
|
+
const targets = scoped.filter((edge) => edge.importedNames === undefined || (importedName !== undefined && edge.importedNames.includes(importedName)));
|
|
3925
|
+
const resolved = targets.flatMap((edge) => context.sourceModules.filter((module) => module.packageName === edge.target.packageName &&
|
|
3926
|
+
path.posix.normalize(module.source) === path.posix.normalize(edge.target.source)));
|
|
3927
|
+
const unique = [
|
|
3928
|
+
...new Map(resolved.map((module) => [`${module.packageName}\0${module.source}\0${module.name}`, module])).values(),
|
|
3929
|
+
];
|
|
3930
|
+
if (unique.length === 1)
|
|
3931
|
+
return unique[0];
|
|
3932
|
+
return specifier.startsWith('.') ? resolveRelativeImportModuleRust(specifier, context, importer) : undefined;
|
|
3933
|
+
}
|
|
3934
|
+
function resolveRelativeImportModuleRust(specifier, context, importer) {
|
|
3935
|
+
const source = path.posix.normalize(path.posix.join(path.posix.dirname(importer.source), specifier.replace(/\.[cm]?js$/u, '.ts')));
|
|
3936
|
+
const candidates = new Set([source, `${source}.ts`, `${source}/index.ts`]);
|
|
3937
|
+
return context.sourceModules.find((module) => module.packageName === importer.packageName && candidates.has(path.posix.normalize(module.source)));
|
|
3938
|
+
}
|
|
3939
|
+
function isRustCompilerModuleIdentityEqual(left, right) {
|
|
3940
|
+
return (left.packageName === right.packageName &&
|
|
3941
|
+
path.posix.normalize(left.source) === path.posix.normalize(right.source) &&
|
|
3942
|
+
left.name === right.name);
|
|
3943
|
+
}
|
|
3944
|
+
function getRustModuleName(module) {
|
|
3945
|
+
return convertSourcePathToRustModuleName(module.source) ?? `_internal_${snakeCase(module.name)}`;
|
|
3946
|
+
}
|
|
3947
|
+
function getRustModuleFilePath(module, sourceModules) {
|
|
3948
|
+
const fileName = `${getRustModuleName(module)}.rs`;
|
|
3949
|
+
const packageNames = new Set(sourceModules.map((candidate) => candidate.packageName));
|
|
3950
|
+
return packageNames.size > 1 ? `${convertPackageNameToRustCrateName(module.packageName)}/src/${fileName}` : fileName;
|
|
3951
|
+
}
|
|
3952
|
+
function safeRustTypeName(name) {
|
|
3953
|
+
const stripped = name.startsWith('#') ? name.slice(1) : name;
|
|
3954
|
+
const value = stripped
|
|
3955
|
+
.split('.')
|
|
3956
|
+
.map((segment) => pascalCase(segment))
|
|
3957
|
+
.join('::');
|
|
3958
|
+
return isRustCompilerKeyword(value) ? `${value}_` : value;
|
|
3959
|
+
}
|
|
3960
|
+
// A union alias becomes a Rust enum only when every alternative is a named record available through
|
|
3961
|
+
// this module's own declarations or imports. Anonymous shapes still have no stable variant identity.
|
|
3962
|
+
function getIrUnionTypeMemberRecordsRust(type, context) {
|
|
3963
|
+
const members = [];
|
|
3964
|
+
for (const member of type.types) {
|
|
3965
|
+
if (member.kind !== 'named' ||
|
|
3966
|
+
member.reference.kind !== 'binding' ||
|
|
3967
|
+
member.reference.binding.space !== 'type' ||
|
|
3968
|
+
member.reference.path.length > 0 ||
|
|
3969
|
+
member.typeArguments.length > 0) {
|
|
3970
|
+
return undefined;
|
|
3971
|
+
}
|
|
3972
|
+
const name = member.reference.binding.name;
|
|
3973
|
+
const declaration = getIrNamedTypeDeclarationLocationRust(member.reference.binding, context, context.module)?.declaration;
|
|
3974
|
+
const properties = declaration?.kind === 'interface' && declaration.typeParameters.length === 0
|
|
3975
|
+
? declaration.properties
|
|
3976
|
+
: declaration?.kind === 'typeAlias' &&
|
|
3977
|
+
declaration.typeParameters.length === 0 &&
|
|
3978
|
+
declaration.type.kind === 'object'
|
|
3979
|
+
? declaration.type.properties
|
|
3980
|
+
: undefined;
|
|
3981
|
+
if (!properties)
|
|
3982
|
+
return undefined;
|
|
3983
|
+
members.push({ name, properties, targetName: getTypeBindingTargetNameRust(member.reference.binding, context) });
|
|
3984
|
+
}
|
|
3985
|
+
return members.length > 1 ? members : undefined;
|
|
3986
|
+
}
|
|
3987
|
+
function getIrNamedTypeDeclarationLocationRust(binding, context, module) {
|
|
3988
|
+
const declarationModule = [module, ...context.sourceModules].find((candidateModule) => candidateModule.declarations.some((candidate) => (candidate.kind === 'interface' || candidate.kind === 'typeAlias') && candidate.binding.id === binding.id));
|
|
3989
|
+
const local = declarationModule?.declarations.find((candidate) => (candidate.kind === 'interface' || candidate.kind === 'typeAlias') && candidate.binding.id === binding.id);
|
|
3990
|
+
if (local && declarationModule)
|
|
3991
|
+
return { declaration: local, module: declarationModule };
|
|
3992
|
+
// A flattened imported declaration can retain a type reference introduced by its own module.
|
|
3993
|
+
// Follow the binding back to that importer rather than assuming every inherited property was
|
|
3994
|
+
// rebound into the subject module.
|
|
3995
|
+
const importer = [module, ...context.sourceModules].find((candidateModule) => candidateModule.imports.some((item) => item.bindings.some((candidate) => candidate.binding.id === binding.id)));
|
|
3996
|
+
const imported = importer?.imports
|
|
3997
|
+
.flatMap((item) => item.bindings.map((candidate) => ({ candidate, specifier: item.specifier })))
|
|
3998
|
+
.find(({ candidate }) => candidate.binding.id === binding.id);
|
|
3999
|
+
if (!imported || imported.candidate.imported === '*' || imported.candidate.imported === 'default')
|
|
4000
|
+
return undefined;
|
|
4001
|
+
const targetModule = resolveImportModuleRust(imported.specifier, imported.candidate.imported, context, importer);
|
|
4002
|
+
const declaration = targetModule?.declarations.find((candidate) => (candidate.kind === 'interface' || candidate.kind === 'typeAlias') &&
|
|
4003
|
+
candidate.binding.name === imported.candidate.imported);
|
|
4004
|
+
return declaration && targetModule ? { declaration, module: targetModule } : undefined;
|
|
4005
|
+
}
|
|
4006
|
+
function getIrCallBorrowedPositionsRust(expression, context) {
|
|
4007
|
+
return expression.callee.kind === 'identifier' && expression.callee.reference.kind === 'binding'
|
|
4008
|
+
? (context.borrowedParameterPositions.get(expression.callee.reference.binding.id) ?? new Set())
|
|
4009
|
+
: new Set();
|
|
4010
|
+
}
|
|
4011
|
+
function getIrClassConcreteBaseRust(declaration, context) {
|
|
4012
|
+
const reference = declaration.extends;
|
|
4013
|
+
if (!reference || reference.kind !== 'named' || reference.reference.kind !== 'binding')
|
|
4014
|
+
return undefined;
|
|
4015
|
+
const binding = reference.reference.binding;
|
|
4016
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'class' && candidate.binding.id === binding.id);
|
|
4017
|
+
return target?.kind === 'class' && !target.abstract ? target : undefined;
|
|
4018
|
+
}
|
|
4019
|
+
function getIrClassStatelessAbstractBaseRust(declaration, context) {
|
|
4020
|
+
const reference = declaration.extends;
|
|
4021
|
+
if (!reference || reference.kind !== 'named' || reference.reference.kind !== 'binding')
|
|
4022
|
+
return undefined;
|
|
4023
|
+
const binding = reference.reference.binding;
|
|
4024
|
+
const target = context.module.declarations.find((candidate) => candidate.kind === 'class' && candidate.binding.id === binding.id);
|
|
4025
|
+
return target?.kind === 'class' &&
|
|
4026
|
+
target.abstract &&
|
|
4027
|
+
target.fields.every((field) => field.abstract) &&
|
|
4028
|
+
!target.extends
|
|
4029
|
+
? target
|
|
4030
|
+
: undefined;
|
|
4031
|
+
}
|
|
4032
|
+
function emitAbstractClassTraitRust(declaration, context) {
|
|
4033
|
+
if (declaration.fields.some((field) => !field.abstract)) {
|
|
4034
|
+
emissionError(context, `abstract class ${declaration.binding.name} carries state a Rust trait cannot hold`);
|
|
4035
|
+
}
|
|
4036
|
+
if (declaration.classConstructor && declaration.classConstructor.body.length > 0) {
|
|
4037
|
+
emissionError(context, `abstract class ${declaration.binding.name} constructor has no Rust trait equivalent`);
|
|
4038
|
+
}
|
|
4039
|
+
const abstractFields = declaration.fields.filter((field) => field.abstract);
|
|
4040
|
+
const fieldNames = new Set(abstractFields.map((field) => field.name));
|
|
4041
|
+
const mutating = getIrClassMutatingMethodNamesRust(declaration);
|
|
4042
|
+
const visibility = declaration.exported || context.apiReferencedBindingIds.has(declaration.binding.id) ? 'pub ' : '';
|
|
4043
|
+
const lines = [
|
|
4044
|
+
`${visibility}trait ${getBindingTargetNameRust(declaration.binding, context)}${emitTypeParameters(declaration.typeParameters, context)} {`,
|
|
4045
|
+
];
|
|
4046
|
+
abstractFields.forEach((field, index) => {
|
|
4047
|
+
if (index > 0)
|
|
4048
|
+
lines.push('');
|
|
4049
|
+
lines.push(` fn ${safeRustValueName(field.name)}(&self) -> ${emitType(field.type, context)};`);
|
|
4050
|
+
});
|
|
4051
|
+
const previousAbstractFieldNames = context.abstractFieldNames;
|
|
4052
|
+
context.abstractFieldNames = fieldNames;
|
|
4053
|
+
declaration.methods.forEach((method, index) => {
|
|
4054
|
+
if (index > 0 || abstractFields.length > 0)
|
|
4055
|
+
lines.push('');
|
|
4056
|
+
const target = getIrClassMethodTargetNameRust(method);
|
|
4057
|
+
const parameters = [
|
|
4058
|
+
...(method.static ? [] : [method.accessor === 'set' || mutating.has(target) ? '&mut self' : '&self']),
|
|
4059
|
+
...method.parameters.map((parameter) => emitParameter(parameter, context)),
|
|
4060
|
+
].join(', ');
|
|
4061
|
+
const returns = method.accessor === 'set' ? '()' : emitType(method.returns, context);
|
|
4062
|
+
const signature = ` fn ${target}${emitTypeParameters(method.typeParameters, context)}(${parameters}) -> ${returns}`;
|
|
4063
|
+
if (method.abstract) {
|
|
4064
|
+
lines.push(`${signature};`);
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
lines.push(`${signature} {`, ...indentSourceLines(emitStatements(method.body, context), 2), ' }');
|
|
4068
|
+
});
|
|
4069
|
+
context.abstractFieldNames = previousAbstractFieldNames;
|
|
4070
|
+
lines.push('}');
|
|
4071
|
+
return lines;
|
|
4072
|
+
}
|
|
4073
|
+
function getIrExpressionClassDeclarationRust(object, context) {
|
|
4074
|
+
if (object.kind !== 'identifier' || object.reference.kind !== 'binding')
|
|
4075
|
+
return undefined;
|
|
4076
|
+
const binding = object.reference.binding;
|
|
4077
|
+
const declaration = context.module.declarations.find((candidate) => candidate.kind === 'class' && candidate.binding.id === binding.id);
|
|
4078
|
+
return declaration?.kind === 'class' ? declaration : undefined;
|
|
4079
|
+
}
|
|
4080
|
+
function getIrExpressionEnumDeclarationRust(object, context) {
|
|
4081
|
+
if (object.kind !== 'identifier' || object.reference.kind !== 'binding')
|
|
4082
|
+
return undefined;
|
|
4083
|
+
const binding = object.reference.binding;
|
|
4084
|
+
const declaration = context.module.declarations.find((candidate) => candidate.kind === 'enum' && candidate.binding.id === binding.id);
|
|
4085
|
+
return declaration?.kind === 'enum' ? declaration : undefined;
|
|
4086
|
+
}
|
|
4087
|
+
function getIrTypeNumericEnumNamespaceNameRust(type, context) {
|
|
4088
|
+
return type.kind === 'named' && type.reference.kind === 'binding'
|
|
4089
|
+
? context.numericEnumNamespaceNames.get(type.reference.binding.id)
|
|
4090
|
+
: undefined;
|
|
4091
|
+
}
|
|
4092
|
+
function getIrExpressionNumericEnumNamespaceNameRust(expression, context) {
|
|
4093
|
+
if (expression.kind === 'identifier' && expression.reference.kind === 'binding') {
|
|
4094
|
+
const type = context.bindingTypes.get(expression.reference.binding.id);
|
|
4095
|
+
return type ? getIrTypeNumericEnumNamespaceNameRust(type, context) : undefined;
|
|
4096
|
+
}
|
|
4097
|
+
if (expression.kind !== 'property')
|
|
4098
|
+
return undefined;
|
|
4099
|
+
if (expression.namespaceMember?.kind === 'binding') {
|
|
4100
|
+
return context.numericEnumNamespaceNames.get(expression.namespaceMember.binding.id);
|
|
4101
|
+
}
|
|
4102
|
+
const declaration = getIrExpressionEnumDeclarationRust(expression.object, context);
|
|
4103
|
+
return declaration ? context.numericEnumNamespaceNames.get(declaration.binding.id) : undefined;
|
|
4104
|
+
}
|
|
4105
|
+
function emitNumericEnumOperandRust(expression, context) {
|
|
4106
|
+
const emitted = emitExpression(expression, context);
|
|
4107
|
+
return getIrExpressionNumericEnumNamespaceNameRust(expression, context) ? `((${emitted}).0 as f64)` : emitted;
|
|
4108
|
+
}
|
|
4109
|
+
function getIrExpressionClassAccessorRust(object, name, accessor, context) {
|
|
4110
|
+
if (object.kind !== 'identifier' || object.reference.kind !== 'binding')
|
|
4111
|
+
return false;
|
|
4112
|
+
const className = context.accessorClassNames.get(object.reference.binding.id);
|
|
4113
|
+
if (!className)
|
|
4114
|
+
return false;
|
|
4115
|
+
const declaration = context.module.declarations.find((candidate) => candidate.kind === 'class' && candidate.binding.name === className);
|
|
4116
|
+
return (declaration?.kind === 'class' &&
|
|
4117
|
+
declaration.methods.some((method) => method.accessor === accessor && method.name === name));
|
|
4118
|
+
}
|
|
4119
|
+
function getIrExpressionTaggedUnionRust(expression, context) {
|
|
4120
|
+
if (expression.kind !== 'identifier' || expression.reference.kind !== 'binding')
|
|
4121
|
+
return undefined;
|
|
4122
|
+
return context.taggedUnionBindingNames.get(expression.reference.binding.id);
|
|
4123
|
+
}
|
|
4124
|
+
function collectPrimitiveUnionBindingsRust(module, context) {
|
|
4125
|
+
for (const declaration of module.declarations) {
|
|
4126
|
+
if (declaration.kind !== 'function')
|
|
4127
|
+
continue;
|
|
4128
|
+
for (const parameter of declaration.parameters) {
|
|
4129
|
+
if (parameter.type.kind !== 'union')
|
|
4130
|
+
continue;
|
|
4131
|
+
const concrete = parameter.type.types.filter((t) => t.kind !== 'null' && t.kind !== 'undefined');
|
|
4132
|
+
if (concrete.length < 2)
|
|
4133
|
+
continue;
|
|
4134
|
+
const enumRecord = getOrCreatePrimitiveUnionEnumRust(concrete, context);
|
|
4135
|
+
if (enumRecord) {
|
|
4136
|
+
context.primitiveUnionBindingIds.set(parameter.binding.id, enumRecord.name);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
if (declaration.returns.kind === 'union') {
|
|
4140
|
+
const concrete = declaration.returns.types.filter((t) => t.kind !== 'null' && t.kind !== 'undefined');
|
|
4141
|
+
if (concrete.length >= 2)
|
|
4142
|
+
getOrCreatePrimitiveUnionEnumRust(concrete, context);
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
analyzeIrModuleTraversal(module, {
|
|
4146
|
+
variable(variable) {
|
|
4147
|
+
if (!('binding' in variable) || !variable.type || variable.type.kind !== 'union')
|
|
4148
|
+
return;
|
|
4149
|
+
const concrete = variable.type.types.filter((t) => t.kind !== 'null' && t.kind !== 'undefined');
|
|
4150
|
+
if (concrete.length < 2)
|
|
4151
|
+
return;
|
|
4152
|
+
const enumRecord = getOrCreatePrimitiveUnionEnumRust(concrete, context);
|
|
4153
|
+
if (enumRecord) {
|
|
4154
|
+
context.primitiveUnionBindingIds.set(variable.binding.id, enumRecord.name);
|
|
4155
|
+
}
|
|
4156
|
+
},
|
|
4157
|
+
});
|
|
4158
|
+
}
|
|
4159
|
+
function emitPrimitiveUnionEnumRust(union) {
|
|
4160
|
+
const lines = [
|
|
4161
|
+
'#[derive(Clone, Debug)]',
|
|
4162
|
+
// Primitive unions are structural products of a public signature rather than source-named
|
|
4163
|
+
// declarations. Keeping the generated enum private makes every exported function that carries
|
|
4164
|
+
// one unusable outside its module, so the representation itself is part of the public ABI.
|
|
4165
|
+
`pub enum ${union.name} {`,
|
|
4166
|
+
...union.variants.map((v) => ` ${v.variantName}(${v.rustType}),`),
|
|
4167
|
+
'}',
|
|
4168
|
+
'',
|
|
4169
|
+
`impl ${union.name} {`,
|
|
4170
|
+
...union.variants.flatMap((v) => [
|
|
4171
|
+
` fn as_${snakeCase(v.variantName)}(&self) -> &${v.rustType} {`,
|
|
4172
|
+
' match self {',
|
|
4173
|
+
` ${union.name}::${v.variantName}(value) => value,`,
|
|
4174
|
+
...(union.variants.length > 1 ? [` _ => panic!("${union.name} is not ${v.variantName}"),`] : []),
|
|
4175
|
+
' }',
|
|
4176
|
+
' }',
|
|
4177
|
+
]),
|
|
4178
|
+
'}',
|
|
4179
|
+
'',
|
|
4180
|
+
`impl std::fmt::Display for ${union.name} {`,
|
|
4181
|
+
" fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {",
|
|
4182
|
+
' match self {',
|
|
4183
|
+
...union.variants.map((v) => ` ${union.name}::${v.variantName}(value) => write!(f, "{}", value),`),
|
|
4184
|
+
' }',
|
|
4185
|
+
' }',
|
|
4186
|
+
'}',
|
|
4187
|
+
];
|
|
4188
|
+
return lines;
|
|
4189
|
+
}
|
|
4190
|
+
function isIrCastTargetNumericRust(type) {
|
|
4191
|
+
if (type.kind === 'primitive')
|
|
4192
|
+
return type.name === 'number' || type.name === 'boolean';
|
|
4193
|
+
return false;
|
|
4194
|
+
}
|
|
4195
|
+
function isIrTypeCopyRust(type) {
|
|
4196
|
+
if (type.kind === 'primitive')
|
|
4197
|
+
return type.name === 'number' || type.name === 'boolean';
|
|
4198
|
+
if (type.kind === 'union') {
|
|
4199
|
+
const nonNull = type.types.filter((member) => member.kind !== 'null' && member.kind !== 'undefined');
|
|
4200
|
+
const sole = nonNull[0];
|
|
4201
|
+
return nonNull.length === 1 && sole !== undefined && isIrTypeCopyRust(sole);
|
|
4202
|
+
}
|
|
4203
|
+
return false;
|
|
4204
|
+
}
|
|
4205
|
+
function emitPrimitiveUnionCastRust(expression, context) {
|
|
4206
|
+
if (expression.type.kind !== 'primitive')
|
|
4207
|
+
return undefined;
|
|
4208
|
+
const targetName = expression.type.name;
|
|
4209
|
+
const primitiveUnion = getIrExpressionPrimitiveUnionRust(expression.expression, context);
|
|
4210
|
+
if (!primitiveUnion)
|
|
4211
|
+
return undefined;
|
|
4212
|
+
const variant = primitiveUnion.variants.find((v) => v.primitiveKind === targetName);
|
|
4213
|
+
if (!variant)
|
|
4214
|
+
return undefined;
|
|
4215
|
+
const emitted = emitExpression(expression.expression, context);
|
|
4216
|
+
if (variant.primitiveKind === 'string')
|
|
4217
|
+
return `${emitted}.as_${snakeCase(variant.variantName)}().clone()`;
|
|
4218
|
+
return `*${emitted}.as_${snakeCase(variant.variantName)}()`;
|
|
4219
|
+
}
|
|
4220
|
+
function emitPrimitiveUnionNarrowedReceiverRust(expression, context) {
|
|
4221
|
+
if (expression.kind !== 'identifier' || !expression.narrowedMember)
|
|
4222
|
+
return undefined;
|
|
4223
|
+
const primitiveUnion = getIrExpressionPrimitiveUnionRust(expression, context);
|
|
4224
|
+
if (!primitiveUnion)
|
|
4225
|
+
return undefined;
|
|
4226
|
+
const variant = primitiveUnion.variants.find((v) => v.primitiveKind === expression.narrowedMember);
|
|
4227
|
+
if (!variant)
|
|
4228
|
+
return undefined;
|
|
4229
|
+
return `${emitIdentifierReferenceRust(expression.reference, context)}.as_${snakeCase(variant.variantName)}()`;
|
|
4230
|
+
}
|
|
4231
|
+
function getIrExpressionPrimitiveUnionRust(expression, context) {
|
|
4232
|
+
if (expression.kind !== 'identifier' || expression.reference.kind !== 'binding')
|
|
4233
|
+
return undefined;
|
|
4234
|
+
const enumName = context.primitiveUnionBindingIds.get(expression.reference.binding.id);
|
|
4235
|
+
if (!enumName)
|
|
4236
|
+
return undefined;
|
|
4237
|
+
for (const union of context.primitiveUnionEnums.values()) {
|
|
4238
|
+
if (union.name === enumName)
|
|
4239
|
+
return union;
|
|
4240
|
+
}
|
|
4241
|
+
return undefined;
|
|
4242
|
+
}
|
|
4243
|
+
function getOrCreatePrimitiveUnionEnumRust(types, context) {
|
|
4244
|
+
if (!types.every((t) => t.kind === 'primitive'))
|
|
4245
|
+
return undefined;
|
|
4246
|
+
const primitives = types.filter((t) => t.kind === 'primitive');
|
|
4247
|
+
const rustPrimitiveInfo = {
|
|
4248
|
+
boolean: { rustType: 'bool', variantName: 'Bool' },
|
|
4249
|
+
number: { rustType: 'f64', variantName: 'F64' },
|
|
4250
|
+
string: { rustType: 'String', variantName: 'Str' },
|
|
4251
|
+
};
|
|
4252
|
+
const variants = primitives.flatMap((p) => {
|
|
4253
|
+
const info = rustPrimitiveInfo[p.name];
|
|
4254
|
+
return info ? [{ primitiveKind: p.name, ...info }] : [];
|
|
4255
|
+
});
|
|
4256
|
+
if (variants.length !== primitives.length)
|
|
4257
|
+
return undefined;
|
|
4258
|
+
const key = variants
|
|
4259
|
+
.map((v) => v.primitiveKind)
|
|
4260
|
+
.sort()
|
|
4261
|
+
.join('|');
|
|
4262
|
+
const existing = context.primitiveUnionEnums.get(key);
|
|
4263
|
+
if (existing)
|
|
4264
|
+
return existing;
|
|
4265
|
+
const name = variants.map((v) => v.variantName).join('Or');
|
|
4266
|
+
const record = { name, variants };
|
|
4267
|
+
context.primitiveUnionEnums.set(key, record);
|
|
4268
|
+
return record;
|
|
4269
|
+
}
|
|
4270
|
+
function getTypeofTypeTestRust(expression, context) {
|
|
4271
|
+
if (expression.operator !== '===' &&
|
|
4272
|
+
expression.operator !== '==' &&
|
|
4273
|
+
expression.operator !== '!==' &&
|
|
4274
|
+
expression.operator !== '!=') {
|
|
4275
|
+
return undefined;
|
|
4276
|
+
}
|
|
4277
|
+
const typeofSide = expression.left.kind === 'unary' && !expression.left.postfix && expression.left.operator === 'typeof'
|
|
4278
|
+
? expression.left
|
|
4279
|
+
: expression.right.kind === 'unary' && !expression.right.postfix && expression.right.operator === 'typeof'
|
|
4280
|
+
? expression.right
|
|
4281
|
+
: undefined;
|
|
4282
|
+
const literalSide = typeofSide === expression.left ? expression.right : expression.left;
|
|
4283
|
+
if (!typeofSide || literalSide.kind !== 'literal' || typeof literalSide.value !== 'string')
|
|
4284
|
+
return undefined;
|
|
4285
|
+
const primitiveUnion = getIrExpressionPrimitiveUnionRust(typeofSide.operand, context);
|
|
4286
|
+
if (!primitiveUnion)
|
|
4287
|
+
return undefined;
|
|
4288
|
+
const variant = primitiveUnion.variants.find((v) => v.primitiveKind === literalSide.value);
|
|
4289
|
+
if (!variant)
|
|
4290
|
+
return undefined;
|
|
4291
|
+
return {
|
|
4292
|
+
enumName: primitiveUnion.name,
|
|
4293
|
+
negated: expression.operator === '!==' || expression.operator === '!=',
|
|
4294
|
+
operand: typeofSide.operand,
|
|
4295
|
+
variantName: variant.variantName,
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
// A Rust enum plus the accessors that make the alternatives reachable: one per alternative for a
|
|
4299
|
+
// reference control flow narrowed, and one per field every alternative shares for a reference it did
|
|
4300
|
+
// not. An accessor rather than a `match` at each site keeps the emitted shape of the source's own
|
|
4301
|
+
// control flow, which is what makes the two targets comparable.
|
|
4302
|
+
function emitTaggedUnionRust(targetName, type, exported, context) {
|
|
4303
|
+
const members = getIrUnionTypeMemberRecordsRust(type, context);
|
|
4304
|
+
if (!members)
|
|
4305
|
+
emissionError(context, 'non-nullable unions require Rust tagged-union lowering');
|
|
4306
|
+
const visibility = exported ? 'pub ' : '';
|
|
4307
|
+
const lines = [emitRustRecordDerive(type.types, context), `${visibility}enum ${targetName} {`];
|
|
4308
|
+
for (const member of members) {
|
|
4309
|
+
lines.push(` ${pascalCase(member.name)}(${member.targetName}),`);
|
|
4310
|
+
}
|
|
4311
|
+
lines.push('}', '', `impl ${targetName} {`);
|
|
4312
|
+
for (const member of members) {
|
|
4313
|
+
lines.push(` ${visibility}fn as_${safeRustValueName(member.name)}(&self) -> &${member.targetName} {`, ' match self {', ` ${targetName}::${pascalCase(member.name)}(value) => value,`, ...(members.length > 1 ? [` _ => panic!("${targetName} is not ${pascalCase(member.name)}"),`] : []), ' }', ' }');
|
|
4314
|
+
}
|
|
4315
|
+
const shared = members[0].properties.filter((property) => members.every((member) => member.properties.some((candidate) => candidate.name === property.name)));
|
|
4316
|
+
for (const property of shared) {
|
|
4317
|
+
lines.push(` ${visibility}fn ${safeRustValueName(property.name)}(&self) -> ${emitType(property.type, context)} {`, ' match self {', ...members.map((member) => ` ${targetName}::${pascalCase(member.name)}(value) => value.${safeRustValueName(property.name)}.clone(),`), ' }', ' }');
|
|
4318
|
+
}
|
|
4319
|
+
lines.push('}');
|
|
4320
|
+
return lines;
|
|
4321
|
+
}
|
|
4322
|
+
function getOrCreateAnonymousUnionEnumRust(types, context) {
|
|
4323
|
+
const key = JSON.stringify({
|
|
4324
|
+
parameters: context.activeTypeParameters.map((parameter) => parameter.binding.id),
|
|
4325
|
+
types,
|
|
4326
|
+
});
|
|
4327
|
+
const existing = context.anonymousUnionEnums.get(key);
|
|
4328
|
+
if (existing)
|
|
4329
|
+
return existing;
|
|
4330
|
+
const record = {
|
|
4331
|
+
name: getGeneratedTargetNameRust('AnonymousUnion', context),
|
|
4332
|
+
typeParameters: context.activeTypeParameters,
|
|
4333
|
+
variants: [],
|
|
4334
|
+
};
|
|
4335
|
+
// Register the identity before rendering payload types so a recursive named alias can lead back
|
|
4336
|
+
// to this generated enum without allocating a second definition.
|
|
4337
|
+
context.anonymousUnionEnums.set(key, record);
|
|
4338
|
+
record.variants.push(...createGeneralUnionVariantsRust(types, context));
|
|
4339
|
+
return record;
|
|
4340
|
+
}
|
|
4341
|
+
function createGeneralUnionVariantsRust(types, context) {
|
|
4342
|
+
const names = new Map();
|
|
4343
|
+
return types.flatMap((type) => {
|
|
4344
|
+
if (type.kind === 'never')
|
|
4345
|
+
return [];
|
|
4346
|
+
const preferred = getGeneralUnionVariantNameRust(type, context);
|
|
4347
|
+
const occurrence = (names.get(preferred) ?? 0) + 1;
|
|
4348
|
+
names.set(preferred, occurrence);
|
|
4349
|
+
const name = occurrence === 1 ? preferred : `${preferred}${String(occurrence)}`;
|
|
4350
|
+
if (type.kind === 'literal' || type.kind === 'null' || type.kind === 'undefined') {
|
|
4351
|
+
return [{ kind: 'unit', name }];
|
|
4352
|
+
}
|
|
4353
|
+
const properties = type.kind === 'object' || type.kind === 'intersection' ? getIrObjectTypePropertiesRust(type, context) : undefined;
|
|
4354
|
+
if (properties) {
|
|
4355
|
+
return [
|
|
4356
|
+
{
|
|
4357
|
+
fields: properties.map((property) => ({
|
|
4358
|
+
name: safeRustValueName(property.name),
|
|
4359
|
+
optional: property.optional,
|
|
4360
|
+
rustType: emitType(property.type, context),
|
|
4361
|
+
})),
|
|
4362
|
+
kind: 'struct',
|
|
4363
|
+
name,
|
|
4364
|
+
},
|
|
4365
|
+
];
|
|
4366
|
+
}
|
|
4367
|
+
return [{ kind: 'tuple', name, rustType: emitType(type, context) }];
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
function getGeneralUnionVariantNameRust(type, context) {
|
|
4371
|
+
if (type.kind === 'literal') {
|
|
4372
|
+
if (typeof type.value === 'boolean')
|
|
4373
|
+
return type.value ? 'True' : 'False';
|
|
4374
|
+
if (typeof type.value === 'number') {
|
|
4375
|
+
return safeRustTypeName(`Number ${String(type.value).replace('-', 'Negative ')}`) || 'Number';
|
|
4376
|
+
}
|
|
4377
|
+
return safeRustTypeName(type.value) || 'String';
|
|
4378
|
+
}
|
|
4379
|
+
if (type.kind === 'named') {
|
|
4380
|
+
return safeRustTypeName(type.reference.kind === 'ambient'
|
|
4381
|
+
? type.reference.name
|
|
4382
|
+
: (type.reference.path.at(-1) ?? type.reference.binding.name));
|
|
4383
|
+
}
|
|
4384
|
+
if (type.kind === 'object' || type.kind === 'intersection') {
|
|
4385
|
+
const properties = getIrObjectTypePropertiesRust(type, context);
|
|
4386
|
+
const discriminant = properties?.find((property) => property.type.kind === 'literal' && typeof property.type.value === 'string');
|
|
4387
|
+
if (discriminant?.type.kind === 'literal' && typeof discriminant.type.value === 'string') {
|
|
4388
|
+
return safeRustTypeName(discriminant.type.value) || 'Object';
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
return {
|
|
4392
|
+
array: 'Array',
|
|
4393
|
+
conditionalFacet: 'ConditionalFacet',
|
|
4394
|
+
function: 'Function',
|
|
4395
|
+
indexedAccess: 'IndexedAccess',
|
|
4396
|
+
intersection: 'Intersection',
|
|
4397
|
+
keyof: 'Key',
|
|
4398
|
+
never: 'Never',
|
|
4399
|
+
null: 'Null',
|
|
4400
|
+
object: 'Object',
|
|
4401
|
+
primitive: type.kind === 'primitive'
|
|
4402
|
+
? { bigint: 'I64', boolean: 'Bool', number: 'F64', string: 'String', symbol: 'Symbol', void: 'Void' }[type.name]
|
|
4403
|
+
: 'Value',
|
|
4404
|
+
tuple: 'Tuple',
|
|
4405
|
+
typeOf: 'TypeOf',
|
|
4406
|
+
undefined: 'Undefined',
|
|
4407
|
+
union: 'Union',
|
|
4408
|
+
unknown: 'Unknown',
|
|
4409
|
+
}[type.kind];
|
|
4410
|
+
}
|
|
4411
|
+
function emitGeneralUnionRust(targetName, variants, typeParameters, exported, context) {
|
|
4412
|
+
const visibility = exported ? 'pub ' : '';
|
|
4413
|
+
const lines = ['#[derive(Clone)]', `${visibility}enum ${targetName}${emitTypeParameters(typeParameters, context)} {`];
|
|
4414
|
+
for (const variant of variants) {
|
|
4415
|
+
if (variant.kind === 'unit') {
|
|
4416
|
+
lines.push(` ${variant.name},`);
|
|
4417
|
+
}
|
|
4418
|
+
else if (variant.kind === 'tuple') {
|
|
4419
|
+
lines.push(` ${variant.name}(${variant.rustType}),`);
|
|
4420
|
+
}
|
|
4421
|
+
else {
|
|
4422
|
+
lines.push(` ${variant.name} {`, ...variant.fields.map((field) => ` ${field.name}: ${field.optional ? `Option<${field.rustType}>` : field.rustType},`), ' },');
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
lines.push('}');
|
|
4426
|
+
return lines;
|
|
4427
|
+
}
|
|
4428
|
+
// Rust spells a constant in upper snake case, and the name is otherwise the source's own.
|
|
4429
|
+
// A getter keeps the source's name, because a call reads the same way; a setter takes a `set_` name,
|
|
4430
|
+
// because the two accessors share one name in the source and Rust has one namespace for both.
|
|
4431
|
+
function getIrClassMethodTargetNameRust(method) {
|
|
4432
|
+
return method.accessor === 'set' ? `set_${safeRustValueName(method.name)}` : safeRustValueName(method.name);
|
|
4433
|
+
}
|
|
4434
|
+
// A runtime type is named bare where it is used and imported once at the top, which is how Rust
|
|
4435
|
+
// spells a dependency. Recording the name at the point of use is what makes the import exact.
|
|
4436
|
+
// Rust braces a use list only when there is more than one name in it, which is what `rustfmt` leaves
|
|
4437
|
+
// behind and therefore what canonical output looks like.
|
|
4438
|
+
function emitUseTreeRust(names) {
|
|
4439
|
+
return names.length === 1 ? names[0] : `{${names.join(', ')}}`;
|
|
4440
|
+
}
|
|
4441
|
+
function recordRuntimeTypeRust(name, context) {
|
|
4442
|
+
context.runtimeTypeNames.add(name);
|
|
4443
|
+
return name;
|
|
4444
|
+
}
|
|
4445
|
+
function constantRustName(name) {
|
|
4446
|
+
return safeRustValueName(name).toUpperCase();
|
|
4447
|
+
}
|
|
4448
|
+
function safeRustValueName(name) {
|
|
4449
|
+
if (name === 'this')
|
|
4450
|
+
return 'self';
|
|
4451
|
+
const stripped = name.startsWith('#') ? name.slice(1) : name;
|
|
4452
|
+
const value = snakeCase(stripped);
|
|
4453
|
+
return isRustCompilerKeyword(value) ? `${value}_` : value;
|
|
4454
|
+
}
|
|
4455
|
+
function pascalCase(value) {
|
|
4456
|
+
return value
|
|
4457
|
+
.split(/[-_]/u)
|
|
4458
|
+
.filter(Boolean)
|
|
4459
|
+
.map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
|
|
4460
|
+
.join('');
|
|
4461
|
+
}
|
|
4462
|
+
function screamingSnakeCase(value) {
|
|
4463
|
+
return snakeCase(value).toUpperCase();
|
|
4464
|
+
}
|
|
4465
|
+
function snakeCase(value) {
|
|
4466
|
+
return value
|
|
4467
|
+
.replace(/([a-z0-9])([A-Z])/gu, '$1_$2')
|
|
4468
|
+
.replace(/([A-Z]+)([A-Z][a-z])/gu, '$1_$2')
|
|
4469
|
+
.replace(/[-\s]+/gu, '_')
|
|
4470
|
+
.toLowerCase();
|
|
4471
|
+
}
|
|
4472
|
+
const rustTypedArrayConstructorNames = new Set([
|
|
4473
|
+
'Float32Array',
|
|
4474
|
+
'Float64Array',
|
|
4475
|
+
'Int8Array',
|
|
4476
|
+
'Int16Array',
|
|
4477
|
+
'Int32Array',
|
|
4478
|
+
'Uint8Array',
|
|
4479
|
+
'Uint8ClampedArray',
|
|
4480
|
+
'Uint16Array',
|
|
4481
|
+
'Uint32Array',
|
|
4482
|
+
]);
|
|
4483
|
+
const rustTypedArrayReceiverNames = new Set([
|
|
4484
|
+
'float32Array',
|
|
4485
|
+
'float64Array',
|
|
4486
|
+
'int8Array',
|
|
4487
|
+
'int16Array',
|
|
4488
|
+
'int32Array',
|
|
4489
|
+
'uint8Array',
|
|
4490
|
+
'uint8ClampedArray',
|
|
4491
|
+
'uint16Array',
|
|
4492
|
+
'uint32Array',
|
|
4493
|
+
]);
|
|
4494
|
+
const rustAssignmentOperatorEmission = {
|
|
4495
|
+
'%=': '%=',
|
|
4496
|
+
'&&=': undefined,
|
|
4497
|
+
'&=': '&=',
|
|
4498
|
+
'**=': undefined,
|
|
4499
|
+
'*=': '*=',
|
|
4500
|
+
'+=': '+=',
|
|
4501
|
+
'-=': '-=',
|
|
4502
|
+
'/=': '/=',
|
|
4503
|
+
'<<=': '<<=',
|
|
4504
|
+
'=': '=',
|
|
4505
|
+
'>>=': '>>=',
|
|
4506
|
+
'>>>=': undefined,
|
|
4507
|
+
'??=': undefined,
|
|
4508
|
+
'^=': '^=',
|
|
4509
|
+
'|=': '|=',
|
|
4510
|
+
'||=': undefined,
|
|
4511
|
+
};
|
|
4512
|
+
const rustBinaryOperatorEmission = {
|
|
4513
|
+
'%': '%',
|
|
4514
|
+
'&': '&',
|
|
4515
|
+
'&&': '&&',
|
|
4516
|
+
'*': '*',
|
|
4517
|
+
'**': undefined,
|
|
4518
|
+
'+': '+',
|
|
4519
|
+
',': undefined,
|
|
4520
|
+
'-': '-',
|
|
4521
|
+
'/': '/',
|
|
4522
|
+
'<': '<',
|
|
4523
|
+
'<<': '<<',
|
|
4524
|
+
'<=': '<=',
|
|
4525
|
+
'!=': '!=',
|
|
4526
|
+
'!==': '!=',
|
|
4527
|
+
'==': '==',
|
|
4528
|
+
'===': '==',
|
|
4529
|
+
'>': '>',
|
|
4530
|
+
'>=': '>=',
|
|
4531
|
+
'>>': '>>',
|
|
4532
|
+
'>>>': undefined,
|
|
4533
|
+
'??': undefined,
|
|
4534
|
+
'^': '^',
|
|
4535
|
+
in: undefined,
|
|
4536
|
+
instanceof: undefined,
|
|
4537
|
+
'|': '|',
|
|
4538
|
+
'||': '||',
|
|
4539
|
+
};
|
|
4540
|
+
const rustPrefixUnaryOperatorDecision = {
|
|
4541
|
+
'!': { emitted: '!' },
|
|
4542
|
+
'+': { emitted: '+' },
|
|
4543
|
+
'++': { refusal: 'prefix ++ requires value-preserving Rust lowering' },
|
|
4544
|
+
'-': { emitted: '-' },
|
|
4545
|
+
'--': { refusal: 'prefix -- requires value-preserving Rust lowering' },
|
|
4546
|
+
delete: { refusal: 'delete requires Rust semantic lowering' },
|
|
4547
|
+
typeof: { refusal: 'typeof requires Rust semantic lowering' },
|
|
4548
|
+
void: { refusal: 'void requires Rust semantic lowering' },
|
|
4549
|
+
'~': { emitted: '!' },
|
|
4550
|
+
};
|
|
4551
|
+
const rustMathSpreadFoldTargets = {
|
|
4552
|
+
max: { folder: 'f64::max', identity: 'f64::NEG_INFINITY' },
|
|
4553
|
+
min: { folder: 'f64::min', identity: 'f64::INFINITY' },
|
|
4554
|
+
};
|
|
4555
|
+
//# sourceMappingURL=rustCompilerBackend.js.map
|