skiptools / skiptools/skip-ui

Binding issues when transpiling

Open
#177 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Swift
Stars
330
Forks
76
Avg merge
3h 6m
Merged PRs (30d)
1

Description

Hello! I'm trying to work with bindings to optional environment objects and bindings to optional fields within those objects. I could get what I want to work with pure Swift, but transpiling fails when trying to get a non optional binding from an optional one.
I'm a SwiftUI newbie myself, so please advise if there's a better or feasible way to approach the problem.
I built this sample to showcase what I'm going through:

import SwiftUI

struct MyModel: Hashable, Codable {
    var optionalVar: String?
    var nonOptionalVar: String
}

final class ModelManager: ObservableObject {
    @Published var optionalModel: MyModel?
    @Published var nonOptionalModel: MyModel

    init(optionalModel: MyModel? = nil, nonOptionalModel: MyModel) {
        self.optionalModel = optionalModel
        self.nonOptionalModel = nonOptionalModel
    }
}

struct ContentView: View {

    @EnvironmentObject var modelManager: ModelManager

    var body: some View {
        VStack {
            TextField("Swift ✅ | Skip ✅", text: $modelManager.nonOptionalModel.nonOptionalVar)
            TextField("Swift ✅ | Skip ✅", text: Binding.unwrap($modelManager.nonOptionalModel.optionalVar, default: ""))

            // Get a nonOptional binding from the optional binding
            if let nonOptionalBinding = Binding($modelManager.optionalModel) {
                TextField("Swift ✅ | Skip ❌", text: nonOptionalBinding.nonOptionalVar)
                TextField("Swift ✅ | Skip ❌", text: Binding.unwrap(nonOptionalBinding.optionalVar, default: ""))
            } else {
                Text("Model is nil!")
            }
        }
    }
}

public extension Binding {
    /// Create a non-optional version of an optional `Binding` with a default value
    /// - Parameters:
    ///   - lhs: The original `Binding<Value?>` (binding to an optional value)
    ///   - rhs: The default value if the original `wrappedValue` is `nil`
    /// - Returns: The `Binding<Value>` (where `Value` is non-optional)
    static func unwrap(_ binding: Binding<Value?>, `default`: Value) -> Binding<Value> {
        Binding {
            binding.wrappedValue ?? `default`
        } set: {
            binding.wrappedValue = $0
        }
    }
}

The failing transpiled code is like this:

// Get a nonOptional binding from the optional binding
                    val matchtarget_0 = Binding(Binding({ _modelManager.wrappedValue.optionalModel }, { it -> _modelManager.wrappedValue.optionalModel = it }))
                    if (matchtarget_0 != null) {
                        val nonOptionalBinding = matchtarget_0
                        TextField(LocalizedStringKey(stringLiteral = "Swift ✅ | Skip ❌"), text = nonOptionalBinding.nonOptionalVar).Compose(composectx)
                        TextField(LocalizedStringKey(stringLiteral = "Swift ✅ | Skip ❌"), text = Binding.unwrap(nonOptionalBinding.optionalVar, default = "")).Compose(composectx)
                    } else {
                        Text(LocalizedStringKey(stringLiteral = "Model is nil!")).Compose(composectx)
                    }

nonOptionalBinding members are reported as unresolved references.

Any help is appreciated!
Thanks for the awesome work on this project!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the SwiftUI sample in the issue and compare its optional Binding conditional with the shown transpiled Kotlin code. Trace how the optional binding and its member accesses are emitted, then verify that nonOptionalBinding members resolve and the sample transpiles successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
kotlin, swift
Domain
compilers, mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.