Skip to content

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

Open
@kciesielski

Description

@kciesielski

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.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions