swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.49k stars 10.35k forks source link

Swift compiler fails to generate diagnostic for wrong function argument in result builder #68005

Open KaiOelfke opened 1 year ago

KaiOelfke commented 1 year ago

Description

I recently had a typo in my code and it took me some time to find the issue, because the Swift Compiler couldn't generate a diagnostic.

The code uses Composable Architecture.

The error message is:

Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs).

import ComposableArchitecture

struct Feature: Reducer {
  struct State: Equatable {
    @PresentationState var destination: Destination.State?
  }
  enum Action: Equatable {
    case destination(PresentationAction)
  }
  struct Destination: Reducer {
    enum State: Equatable {
    }
    enum Action: Equatable {
    }
    var body: some ReducerOf {
      EmptyReducer()
    }
  }
  var body: some ReducerOf {
    Reduce { state, action in
      return .none
    }
    .ifLet(\.destination, action: /Action.destination) { // \.destination is the wrong argument
      Destination()
    }
  }
}

// Signature of ifLet

public func ifLet<DestinationState, DestinationAction, Destination: Reducer>(
    _ toPresentationState: WritableKeyPath<State, PresentationState<DestinationState>>,
    action toPresentationAction: CasePath<Action, PresentationAction<DestinationAction>>,
    @ReducerBuilder<DestinationState, DestinationAction> destination: () -> Destination,
    fileID: StaticString = #fileID,
    line: UInt = #line
  ) -> _PresentationReducer<Self, Destination> { ... }

// \.destination is WritableKeyPath<Feature.State, Feature.Destination.State?>
// \.$destination is WritableKeyPath<Feature.State, PresentationState<Feature.Destination.State>>

What's wrong here is the first argument of the ifLet function. It should be .$destination to use the projected value of the @PresentationState property wrapper. So this is a single character typo / bug, but it's hard to diagnose without a helpful compiler message.

Steps to reproduce

Compile the code above e.g. with TCA version 1.0.0.

Expected behavior

Get an error message that the ifLet function expects a different type or that the argument is wrong. Ideally, if possible, the compiler should infer that .destination is a KeyPath to a property wrapper value and that the projected value fits the function signature so it would suggest a fix it to insert the missing $ character.

Environment

xedin commented 1 year ago

@amritpan I think this might be fixed but the changes you are working on.