Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] type arguments can't be determined from Any #472

Open
kciesielski opened this issue Jun 13, 2023 · 0 comments
Open

[bug] type arguments can't be determined from Any #472

kciesielski opened this issue Jun 13, 2023 · 0 comments
Assignees
Labels

Comments

@kciesielski
Copy link
Member

kciesielski commented Jun 13, 2023

In 1.3.1, Magnolia usages in Tapir generate warnings like:

[warn] /xxx/src/core/impl.scala: the type test for Option[com.softwaremill.Endpoints.UserId]
 cannot be checked at runtime because its type arguments can't be determined from Any

I have added a workaround with suppression in #473, but a proper fix may be needed in the future.

Detailed problem description

When deriving default values for case class members, Magnolia checks if there's a user-defined default, otherwise it falls back to a default based on field's type. For example, for case class Example(field: Int) it would derive a default of Example(0). However, there's an issue when dealing with generic classes with generic field types, where user defined default exists:

case class Example[A](field: Option[A] = Some("A"))
val defaultVal = HasDefault.derived[Example[Int]].defaultValue.right.get
// defaultVal == Example(Some("A")), wrong! Should be Example(None)
val fieldVal: Int = defaultVal.field.get // compiles, but throws a ClassCastException

Consequences

The Example(Some("A")) default value is incorrect, because object's type is Example[Int]. This would throw a ClassCastException on resolving the field's wrapped value. Using generic types with default values like this doesn't seem like a common scenario, so severity of this issue is very low.

Cause

In core.paramsFromMaps default values for case class fields are passed in an argument of type defaults: Map[String, Option[() => Any]]. These Any values are unsafely casted to type parameters in the safeCast method, which may cause casting for example an Option[String] to an Option[Int]. Instead, for a default param that doesn't match the type, a None should be returned, causing a fallback type's proper default value.

Possible solution

A proper resolution might require enriching defaults: Map[String, Option[() => Any]] with type information, which, compared to actual type (in the method called p) would allow to detect a mismatch, causing a fallback to None. This requires nontrivial changes to the macro which generates defaults.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant