Repository: apple/swift
File: lib/Sema/TypeCheckPropertyWrapper.cpp (C++)

Code before:
  // the subscript must be as accessible as the nominal type.
  if (isDeclNotAsAccessibleAsParent(subscript, nominal)) {
    subscript->diagnose(diag::property_wrapper_type_requirement_not_accessible,
                        subscript->getFormalAccess(),
                        subscript, nominal->getDeclaredType(),
                        nominal->getFormalAccess());
    return nullptr;
  }

  return subscript;
}

/// Validate key path parameter types for an enclosing-self subscript.
static bool validateEnclosingSelfSubscript(SubscriptDecl *subscript) {
  auto *indices = subscript->getIndices();
  if (!indices || indices->size() != 3)
    return false;

  bool isValid = true;
  for (unsigned i : {1U, 2U}) {
    auto *param = indices->get(i);
    auto paramTy = param->getInterfaceType();
    if (paramTy->is<ErrorType>())
      continue;

    if (!paramTy->isReferenceWritableKeyPath()) {
      param->diagnose(diag::property_wrapper_enclosing_self_subscript_keypath_type,
                      param->getArgumentName(), paramTy);
      isValid = false;
    }
  }

  return isValid;
}

PropertyWrapperTypeInfo
PropertyWrapperTypeInfoRequest::evaluate(
    Evaluator &eval, NominalTypeDecl *nominal) const {
  // We must have the @propertyWrapper attribute to continue.
  if (!nominal->getAttrs().hasAttribute<PropertyWrapperAttr>()) {
    return PropertyWrapperTypeInfo();
  }

  // Look for a non-static property named "wrappedValue" in the property
  // wrapper type.
  ASTContext &ctx = nominal->getASTContext();
  auto valueVar =
      findValueProperty(ctx, nominal, ctx.Id_wrappedValue,
                        /*allowMissing=*/false);
  if (!valueVar)
    return PropertyWrapperTypeInfo();

Review comment (refactor):
See my comment about `WritableKeyPath` and also as a separate note this loop could be simplified down if you extract the actual checking into a local function and just call it twice.

Code after:
  // the subscript must be as accessible as the nominal type.
  if (isDeclNotAsAccessibleAsParent(subscript, nominal)) {
    subscript->diagnose(diag::property_wrapper_type_requirement_not_accessible,
                        subscript->getFormalAccess(),
                        subscript, nominal->getDeclaredType(),
                        nominal->getFormalAccess());
    return nullptr;
  }

  return subscript;
}

/// Validate key path parameter types for an enclosing-self subscript.
static bool validateEnclosingSelfSubscript(SubscriptDecl *subscript) {
  auto *indices = subscript->getIndices();
  if (!indices || indices->size() != 3)
    return false;

  auto checkKeyPathParam = [&](unsigned index) -> bool {
    auto *param = indices->get(index);
    auto paramTy = param->getInterfaceType();
    if (paramTy->hasError())
      return true;

    if (!paramTy->isWritableKeyPath() && !paramTy->isReferenceWritableKeyPath()) {
      param->diagnose(diag::property_wrapper_enclosing_self_subscript_keypath_type,
                      param->getArgumentName(), paramTy);
      return false;
    }
    return true;
  };

  bool wrappedOrProjectedOK = checkKeyPathParam(/*wrapped/projected*/ 1);
  bool storageOK = checkKeyPathParam(/*storage*/ 2);
  return wrappedOrProjectedOK && storageOK;
}

PropertyWrapperTypeInfo
PropertyWrapperTypeInfoRequest::evaluate(
    Evaluator &eval, NominalTypeDecl *nominal) const {
  // We must have the @propertyWrapper attribute to continue.
  if (!nominal->getAttrs().hasAttribute<PropertyWrapperAttr>()) {
    return PropertyWrapperTypeInfo();
  }

  // Look for a non-static property named "wrappedValue" in the property
  // wrapper type.
  ASTContext &ctx = nominal->getASTContext();
  auto valueVar =
      findValueProperty(ctx, nominal, ctx.Id_wrappedValue,
                        /*allowMissing=*/false);