diff --git a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/NumberTypeUtils.scala b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/NumberTypeUtils.scala index a9cb2846918..647f169c393 100644 --- a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/NumberTypeUtils.scala +++ b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/NumberTypeUtils.scala @@ -15,9 +15,9 @@ object NumberTypeUtils { else if (typ == Typed[java.lang.Double]) java.lang.Double.valueOf(0) else if (typ == Typed[java.math.BigDecimal]) java.math.BigDecimal.ZERO // in case of some unions - else if (typ.canBeImplicitlyConvertedTo(Typed[java.lang.Integer])) java.lang.Integer.valueOf(0) + else if (typ.canBeConvertedTo(Typed[java.lang.Integer])) java.lang.Integer.valueOf(0) // double is quite safe - it can be converted to any Number - else if (typ.canBeImplicitlyConvertedTo(Typed[Number])) java.lang.Double.valueOf(0) + else if (typ.canBeConvertedTo(Typed[Number])) java.lang.Double.valueOf(0) else throw new IllegalArgumentException(s"Not expected type: ${typ.display}, should be Number") } diff --git a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/StrictConversionDeterminer.scala b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/StrictConversionDeterminer.scala index ca310a7a792..63573cece27 100644 --- a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/StrictConversionDeterminer.scala +++ b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/StrictConversionDeterminer.scala @@ -1,18 +1,49 @@ package pl.touk.nussknacker.engine.api.typed import cats.data.Validated.condNel -import cats.data.ValidatedNel +import cats.data.{NonEmptyList, Validated, ValidatedNel} +import cats.implicits.catsSyntaxValidatedId import org.apache.commons.lang3.ClassUtils import pl.touk.nussknacker.engine.api.typed.supertype.NumberTypesPromotionStrategy.AllNumbers -import pl.touk.nussknacker.engine.api.typed.typing.{SingleTypingResult, TypedClass, TypingResult} +import pl.touk.nussknacker.engine.api.typed.typing._ object StrictConversionDeterminer { def canBeConvertedTo(givenType: TypingResult, superclassCandidate: TypingResult): ValidatedNel[String, Unit] = { - ImplicitConversionDeterminer.canBeConvertedTo(givenType, superclassCandidate) + (givenType, superclassCandidate) match { + case (_, Unknown) => ().validNel + case (Unknown, _) => ().validNel + case (TypedNull, other) => canNullBeConvertedTo(other) + case (_, TypedNull) => s"No type can be subclass of ${TypedNull.display}".invalidNel + case (given: SingleTypingResult, superclass: TypedUnion) => + canBeConvertedTo(NonEmptyList.one(given), superclass.possibleTypes) + case (given: TypedUnion, superclass: SingleTypingResult) => + canBeConvertedTo(given.possibleTypes, NonEmptyList.one(superclass)) + case (given: SingleTypingResult, superclass: SingleTypingResult) => singleCanBeConvertedTo(given, superclass) + case (given: TypedUnion, superclass: TypedUnion) => + canBeConvertedTo(given.possibleTypes, superclass.possibleTypes) + } + } + + def canBeConvertedTo( + givenTypes: NonEmptyList[SingleTypingResult], + superclassCandidates: NonEmptyList[SingleTypingResult] + ): ValidatedNel[String, Unit] = { + // Would be more safety to do givenTypes.forAll(... superclassCandidates.exists ...) - we wil protect against + // e.g. (String | Int).canBeSubclassOf(String) which can fail in runtime for Int, but on the other hand we can't block user's intended action. + // He/she could be sure that in this type, only String will appear. He/she also can't easily downcast (String | Int) to String so leaving here + // "double exists" looks like a good tradeoff + condNel( + givenTypes.exists(given => superclassCandidates.exists(singleCanBeConvertedTo(given, _).isValid)), + (), + s"""None of the following types: + |${givenTypes.map(" - " + _.display).toList.mkString(",\n")} + |can be a subclass of any of: + |${superclassCandidates.map(" - " + _.display).toList.mkString(",\n")}""".stripMargin + ) } - def singleCanBeConvertedTo( + def singleCanBeConvertedTo( givenType: SingleTypingResult, superclassCandidate: SingleTypingResult ): ValidatedNel[String, Unit] = { @@ -22,11 +53,26 @@ object StrictConversionDeterminer { isStrictSubclass(givenClass, givenSuperclas) } - def canBeStrictSubclassOf(givenType: TypingResult, superclassCandidate: TypingResult): ValidatedNel[String, Unit] = { - this.canBeConvertedTo(givenType, superclassCandidate) + private def canNullBeConvertedTo(result: TypingResult): ValidatedNel[String, Unit] = result match { + // TODO: Null should not be subclass of typed map that has all values assigned. + case TypedObjectWithValue(_, _) => s"${TypedNull.display} cannot be subclass of type with value".invalidNel + case _ => ().validNel + } + + def isStrictSubclass(givenClass: TypedClass, givenSuperclass: TypedClass): Validated[NonEmptyList[String], Unit] = { + condNel( + givenClass == givenSuperclass, + (), + f"${givenClass.display} and ${givenSuperclass.display} are not the same" + ) orElse + condNel( + isAssignable(givenClass.klass, givenSuperclass.klass), + (), + s"${givenClass.klass} is not assignable from ${givenSuperclass.klass}" + ) } - override def isAssignable(from: Class[_], to: Class[_]): Boolean = { + def isAssignable(from: Class[_], to: Class[_]): Boolean = { (from, to) match { case (f, t) if ClassUtils.isAssignable(f, t, true) => true // Number double check by hand because lang3 can incorrectly throw false when dealing with java types diff --git a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/TypeConversionHandler.scala b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/TypeConversionHandler.scala index 8312ff4ee15..4fbe1ce0724 100644 --- a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/TypeConversionHandler.scala +++ b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/TypeConversionHandler.scala @@ -108,7 +108,7 @@ object TypeConversionHandler { ClassUtils.isAssignable(boxedGivenClass, classOf[Number], true) case candidate if isDecimalNumber(candidate) => - SubclassDeterminer.isAssignable(boxedGivenClass, candidate) + StrictConversionDeterminer.isAssignable(boxedGivenClass, candidate) case _ => false } diff --git a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/typing.scala b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/typing.scala index c2be6cdcf72..2ccf863a86a 100644 --- a/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/typing.scala +++ b/components-api/src/main/scala/pl/touk/nussknacker/engine/api/typed/typing.scala @@ -27,11 +27,18 @@ object typing { // TODO: Rename to Typed, maybe NuType? sealed trait TypingResult { - final def canBeImplicitlyConvertedTo(typingResult: TypingResult): Boolean = + /** + * Checks if there exists a conversion to a given typingResult, with possible loss of precision, e.g. long to int. + * If you need to retain conversion precision, use canBeStrictlyConvertedTo + */ + final def canBeConvertedTo(typingResult: TypingResult): Boolean = ImplicitConversionDeterminer.canBeConvertedTo(this, typingResult).isValid - def canBeStrictSubclassOf(typingResult: TypingResult): Boolean = - SubclassDeterminer.canBeStrictSubclassOf(this, typingResult).isValid + /** + * Checks if the conversion to a given typingResult can be made without loss of precision + */ + final def canBeStrictlyConvertedTo(typingResult: TypingResult): Boolean = + StrictConversionDeterminer.canBeConvertedTo(this, typingResult).isValid def valueOpt: Option[Any] @@ -463,7 +470,7 @@ object typing { def unapply(typingResult: TypingResult): Option[TypingResultTypedValue[T]] = { Option(typingResult) - .filter(_.canBeImplicitlyConvertedTo(Typed.fromDetailedType[T])) + .filter(_.canBeConvertedTo(Typed.fromDetailedType[T])) .map(new TypingResultTypedValue(_)) } diff --git a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/SubclassDeterminerSpec.scala b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/SubclassDeterminerSpec.scala index be7be9e72f7..bcdc5a24bfe 100644 --- a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/SubclassDeterminerSpec.scala +++ b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/SubclassDeterminerSpec.scala @@ -7,21 +7,21 @@ import org.scalatest.matchers.should.Matchers class SubclassDeterminerSpec extends AnyFunSuite with Matchers { test("Should validate assignability for decimal types") { - SubclassDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Integer]) shouldBe false - SubclassDeterminer.isAssignable(classOf[Number], classOf[Integer]) shouldBe false - SubclassDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Short]) shouldBe false + StrictConversionDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Integer]) shouldBe false + StrictConversionDeterminer.isAssignable(classOf[Number], classOf[Integer]) shouldBe false + StrictConversionDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Short]) shouldBe false - SubclassDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Long]) shouldBe true - SubclassDeterminer.isAssignable(classOf[Integer], classOf[Number]) shouldBe true - SubclassDeterminer.isAssignable(classOf[java.lang.Short], classOf[Integer]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Long]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[Integer], classOf[Number]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[java.lang.Short], classOf[Integer]) shouldBe true } test("Should validate assignability for numerical types") { - SubclassDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Double]) shouldBe true - SubclassDeterminer.isAssignable(classOf[java.lang.Float], classOf[Double]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Double]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[java.lang.Float], classOf[Double]) shouldBe true - SubclassDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Float]) shouldBe true - SubclassDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Double]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[Integer], classOf[java.lang.Float]) shouldBe true + StrictConversionDeterminer.isAssignable(classOf[java.lang.Long], classOf[java.lang.Double]) shouldBe true } // to check if autoboxing lang3 is failing - we can remove our fallback from SubclassDeterminer.isAssignable if the lib works properly diff --git a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypedFromInstanceTest.scala b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypedFromInstanceTest.scala index f3e50d76e35..b1d98cd537d 100644 --- a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypedFromInstanceTest.scala +++ b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypedFromInstanceTest.scala @@ -60,20 +60,20 @@ class TypedFromInstanceTest extends AnyFunSuite with Matchers with LoneElement w } test("should type empty list") { - Typed.fromInstance(Nil).canBeImplicitlyConvertedTo(Typed(classOf[List[_]])) shouldBe true - Typed.fromInstance(Nil.asJava).canBeImplicitlyConvertedTo(Typed(classOf[java.util.List[_]])) shouldBe true + Typed.fromInstance(Nil).canBeConvertedTo(Typed(classOf[List[_]])) shouldBe true + Typed.fromInstance(Nil.asJava).canBeConvertedTo(Typed(classOf[java.util.List[_]])) shouldBe true } test("should type lists and return union of types coming from all elements") { def checkTypingResult(obj: Any, klass: Class[_], paramTypingResult: TypingResult): Unit = { val typingResult = Typed.fromInstance(obj) - typingResult.canBeImplicitlyConvertedTo(Typed(klass)) shouldBe true + typingResult.canBeConvertedTo(Typed(klass)) shouldBe true typingResult.withoutValue .asInstanceOf[TypedClass] .params .loneElement - .canBeImplicitlyConvertedTo(paramTypingResult) shouldBe true + .canBeConvertedTo(paramTypingResult) shouldBe true } def checkNotASubclassOfOtherParamTypingResult(obj: Any, otherParamTypingResult: TypingResult): Unit = { @@ -82,7 +82,7 @@ class TypedFromInstanceTest extends AnyFunSuite with Matchers with LoneElement w .asInstanceOf[TypedClass] .params .loneElement - .canBeImplicitlyConvertedTo(otherParamTypingResult) shouldBe false + .canBeConvertedTo(otherParamTypingResult) shouldBe false } val listOfSimpleObjects = List[Any](1.1, 2) diff --git a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypingResultSpec.scala b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypingResultSpec.scala index 189698008f7..1581edf488c 100644 --- a/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypingResultSpec.scala +++ b/components-api/src/test/scala/pl/touk/nussknacker/engine/api/typed/TypingResultSpec.scala @@ -32,33 +32,33 @@ class TypingResultSpec test("determine if can be subclass for typed object") { - typeMap("field1" -> Typed[String], "field2" -> Typed[Int]).canBeImplicitlyConvertedTo( + typeMap("field1" -> Typed[String], "field2" -> Typed[Int]).canBeConvertedTo( typeMap("field1" -> Typed[String]) ) shouldBe true - typeMap("field1" -> Typed[String]).canBeImplicitlyConvertedTo( + typeMap("field1" -> Typed[String]).canBeConvertedTo( typeMap("field1" -> Typed[String], "field2" -> Typed[Int]) ) shouldBe false - typeMap("field1" -> Typed[Int]).canBeImplicitlyConvertedTo( + typeMap("field1" -> Typed[Int]).canBeConvertedTo( typeMap("field1" -> Typed[String]) ) shouldBe false - typeMap("field1" -> Typed[Int]).canBeImplicitlyConvertedTo( + typeMap("field1" -> Typed[Int]).canBeConvertedTo( typeMap("field1" -> Typed[Number]) ) shouldBe true - typeMap("field1" -> list(typeMap("field2" -> Typed[String], "field3" -> Typed[Int]))).canBeImplicitlyConvertedTo( + typeMap("field1" -> list(typeMap("field2" -> Typed[String], "field3" -> Typed[Int]))).canBeConvertedTo( typeMap("field1" -> list(typeMap("field2" -> Typed[String]))) ) shouldBe true - typeMap("field1" -> list(typeMap("field2a" -> Typed[String], "field3" -> Typed[Int]))).canBeImplicitlyConvertedTo( + typeMap("field1" -> list(typeMap("field2a" -> Typed[String], "field3" -> Typed[Int]))).canBeConvertedTo( typeMap("field1" -> list(typeMap("field2" -> Typed[String]))) ) shouldBe false - typeMap("field1" -> Typed[String]).canBeImplicitlyConvertedTo(Typed[java.util.Map[_, _]]) shouldBe true + typeMap("field1" -> Typed[String]).canBeConvertedTo(Typed[java.util.Map[_, _]]) shouldBe true - Typed[java.util.Map[_, _]].canBeImplicitlyConvertedTo(typeMap("field1" -> Typed[String])) shouldBe false + Typed[java.util.Map[_, _]].canBeConvertedTo(typeMap("field1" -> Typed[String])) shouldBe false } test("extract Unknown value type when no super matching supertype found among all fields of Record") { @@ -76,78 +76,78 @@ class TypingResultSpec } test("determine if can be subclass for typed unions") { - Typed(Typed[String], Typed[Int]).canBeImplicitlyConvertedTo(Typed[Int]) shouldBe true - Typed[Int].canBeImplicitlyConvertedTo(Typed(Typed[String], Typed[Int])) shouldBe true + Typed(Typed[String], Typed[Int]).canBeConvertedTo(Typed[Int]) shouldBe true + Typed[Int].canBeConvertedTo(Typed(Typed[String], Typed[Int])) shouldBe true - Typed(Typed[String], Typed[Int]).canBeImplicitlyConvertedTo(Typed(Typed[Long], Typed[Int])) shouldBe true + Typed(Typed[String], Typed[Int]).canBeConvertedTo(Typed(Typed[Long], Typed[Int])) shouldBe true } test("determine if can be subclass for unknown") { - Unknown.canBeImplicitlyConvertedTo(Typed[Int]) shouldBe true - Typed[Int].canBeImplicitlyConvertedTo(Unknown) shouldBe true + Unknown.canBeConvertedTo(Typed[Int]) shouldBe true + Typed[Int].canBeConvertedTo(Unknown) shouldBe true - Unknown.canBeImplicitlyConvertedTo(Typed(Typed[String], Typed[Int])) shouldBe true - Typed(Typed[String], Typed[Int]).canBeImplicitlyConvertedTo(Unknown) shouldBe true + Unknown.canBeConvertedTo(Typed(Typed[String], Typed[Int])) shouldBe true + Typed(Typed[String], Typed[Int]).canBeConvertedTo(Unknown) shouldBe true - Unknown.canBeImplicitlyConvertedTo(typeMap("field1" -> Typed[String])) shouldBe true - typeMap("field1" -> Typed[String]).canBeImplicitlyConvertedTo(Unknown) shouldBe true + Unknown.canBeConvertedTo(typeMap("field1" -> Typed[String])) shouldBe true + typeMap("field1" -> Typed[String]).canBeConvertedTo(Unknown) shouldBe true } test("determine if can be subclass for class") { Typed .fromDetailedType[java.util.List[BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.List[BigDecimal]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.List[BigDecimal]]) shouldBe true Typed .fromDetailedType[java.util.List[BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.List[Number]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.List[Number]]) shouldBe true Typed .fromDetailedType[java.util.List[Number]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.List[BigDecimal]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[java.util.List[BigDecimal]]) shouldBe false Typed .fromDetailedType[java.util.Map[BigDecimal, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe true Typed .fromDetailedType[java.util.Map[BigDecimal, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, Number]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, Number]]) shouldBe true Typed .fromDetailedType[java.util.Map[BigDecimal, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[Number, Number]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[Number, Number]]) shouldBe false Typed .fromDetailedType[java.util.Map[Number, Number]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false Typed .fromDetailedType[java.util.Map[Number, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false Typed .fromDetailedType[java.util.Map[BigDecimal, Number]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe false Typed .fromDetailedType[java.util.Map[BigDecimal, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[_, BigDecimal]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[_, BigDecimal]]) shouldBe true Typed .fromDetailedType[java.util.Map[_, BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[java.util.Map[BigDecimal, BigDecimal]]) shouldBe true // For arrays it might be tricky Typed .fromDetailedType[Array[BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[Array[BigDecimal]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[Array[BigDecimal]]) shouldBe true Typed .fromDetailedType[Array[BigDecimal]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[Array[Number]]) shouldBe true + .canBeConvertedTo(Typed.fromDetailedType[Array[Number]]) shouldBe true Typed .fromDetailedType[Array[Number]] - .canBeImplicitlyConvertedTo(Typed.fromDetailedType[Array[BigDecimal]]) shouldBe false + .canBeConvertedTo(Typed.fromDetailedType[Array[BigDecimal]]) shouldBe false } test("determine if numbers can be converted") { - Typed[Int].canBeImplicitlyConvertedTo(Typed[Long]) shouldBe true - Typed[Long].canBeImplicitlyConvertedTo(Typed[Int]) shouldBe true - Typed[Long].canBeImplicitlyConvertedTo(Typed[Double]) shouldBe true - Typed[Double].canBeImplicitlyConvertedTo(Typed[Long]) shouldBe false - Typed[java.math.BigDecimal].canBeImplicitlyConvertedTo(Typed[Long]) shouldBe true - Typed[Long].canBeImplicitlyConvertedTo(Typed[java.math.BigDecimal]) shouldBe true + Typed[Int].canBeConvertedTo(Typed[Long]) shouldBe true + Typed[Long].canBeConvertedTo(Typed[Int]) shouldBe true + Typed[Long].canBeConvertedTo(Typed[Double]) shouldBe true + Typed[Double].canBeConvertedTo(Typed[Long]) shouldBe false + Typed[java.math.BigDecimal].canBeConvertedTo(Typed[Long]) shouldBe true + Typed[Long].canBeConvertedTo(Typed[java.math.BigDecimal]) shouldBe true } test("find common supertype for simple types") { @@ -303,22 +303,22 @@ class TypingResultSpec test("determine if can be subclass for tagged value") { Typed .tagged(Typed.typedClass[String], "tag1") - .canBeImplicitlyConvertedTo(Typed.tagged(Typed.typedClass[String], "tag1")) shouldBe true + .canBeConvertedTo(Typed.tagged(Typed.typedClass[String], "tag1")) shouldBe true Typed .tagged(Typed.typedClass[String], "tag1") - .canBeImplicitlyConvertedTo(Typed.tagged(Typed.typedClass[String], "tag2")) shouldBe false + .canBeConvertedTo(Typed.tagged(Typed.typedClass[String], "tag2")) shouldBe false Typed .tagged(Typed.typedClass[String], "tag1") - .canBeImplicitlyConvertedTo(Typed.tagged(Typed.typedClass[Integer], "tag1")) shouldBe false - Typed.tagged(Typed.typedClass[String], "tag1").canBeImplicitlyConvertedTo(Typed.typedClass[String]) shouldBe true - Typed.typedClass[String].canBeImplicitlyConvertedTo(Typed.tagged(Typed.typedClass[String], "tag1")) shouldBe false + .canBeConvertedTo(Typed.tagged(Typed.typedClass[Integer], "tag1")) shouldBe false + Typed.tagged(Typed.typedClass[String], "tag1").canBeConvertedTo(Typed.typedClass[String]) shouldBe true + Typed.typedClass[String].canBeConvertedTo(Typed.tagged(Typed.typedClass[String], "tag1")) shouldBe false } test("determine if can be subclass for null") { - TypedNull.canBeImplicitlyConvertedTo(Typed[Int]) shouldBe true - TypedNull.canBeImplicitlyConvertedTo(Typed.fromInstance(4)) shouldBe false - TypedNull.canBeImplicitlyConvertedTo(TypedNull) shouldBe true - Typed[String].canBeImplicitlyConvertedTo(TypedNull) shouldBe false + TypedNull.canBeConvertedTo(Typed[Int]) shouldBe true + TypedNull.canBeConvertedTo(Typed.fromInstance(4)) shouldBe false + TypedNull.canBeConvertedTo(TypedNull) shouldBe true + Typed[String].canBeConvertedTo(TypedNull) shouldBe false } test("should deeply extract typ parameters") { @@ -337,20 +337,20 @@ class TypingResultSpec } test("determine if can be subclass for object with value") { - Typed.fromInstance(45).canBeImplicitlyConvertedTo(Typed.typedClass[Long]) shouldBe true - Typed.fromInstance(29).canBeImplicitlyConvertedTo(Typed.typedClass[String]) shouldBe false - Typed.fromInstance(78).canBeImplicitlyConvertedTo(Typed.fromInstance(78)) shouldBe true - Typed.fromInstance(12).canBeImplicitlyConvertedTo(Typed.fromInstance(15)) shouldBe false - Typed.fromInstance(41).canBeImplicitlyConvertedTo(Typed.fromInstance("t")) shouldBe false - Typed.typedClass[String].canBeImplicitlyConvertedTo(Typed.fromInstance("t")) shouldBe true + Typed.fromInstance(45).canBeConvertedTo(Typed.typedClass[Long]) shouldBe true + Typed.fromInstance(29).canBeConvertedTo(Typed.typedClass[String]) shouldBe false + Typed.fromInstance(78).canBeConvertedTo(Typed.fromInstance(78)) shouldBe true + Typed.fromInstance(12).canBeConvertedTo(Typed.fromInstance(15)) shouldBe false + Typed.fromInstance(41).canBeConvertedTo(Typed.fromInstance("t")) shouldBe false + Typed.typedClass[String].canBeConvertedTo(Typed.fromInstance("t")) shouldBe true } test("determine if can be subclass for object with value - use conversion") { - Typed.fromInstance("2007-12-03").canBeImplicitlyConvertedTo(Typed.typedClass[LocalDate]) shouldBe true - Typed.fromInstance("2007-12-03T10:15:30").canBeImplicitlyConvertedTo(Typed.typedClass[LocalDateTime]) shouldBe true + Typed.fromInstance("2007-12-03").canBeConvertedTo(Typed.typedClass[LocalDate]) shouldBe true + Typed.fromInstance("2007-12-03T10:15:30").canBeConvertedTo(Typed.typedClass[LocalDateTime]) shouldBe true - Typed.fromInstance("2007-12-03-qwerty").canBeImplicitlyConvertedTo(Typed.typedClass[LocalDate]) shouldBe false - Typed.fromInstance("2007-12-03").canBeImplicitlyConvertedTo(Typed.typedClass[Currency]) shouldBe false + Typed.fromInstance("2007-12-03-qwerty").canBeConvertedTo(Typed.typedClass[LocalDate]) shouldBe false + Typed.fromInstance("2007-12-03").canBeConvertedTo(Typed.typedClass[Currency]) shouldBe false } test("determinate if can be superclass for objects with value") { @@ -449,7 +449,7 @@ class TypingResultSpec logger.trace(s"Checking: ${input.display}") withClue(s"Input: ${input.display};") { - input.canBeImplicitlyConvertedTo(input) shouldBe true + input.canBeConvertedTo(input) shouldBe true val superType = CommonSupertypeFinder.Default.commonSupertype(input, input) withClue(s"Supertype: ${superType.display};") { superType shouldEqual input @@ -463,11 +463,11 @@ class TypingResultSpec logger.trace(s"Checking: ${input.display}") withClue(s"Input: ${input.display};") { - input.canBeImplicitlyConvertedTo(input) shouldBe true + input.canBeConvertedTo(input) shouldBe true val superType = CommonSupertypeFinder.Default.commonSupertype(input, input) withClue(s"Supertype: ${superType.display};") { // We generate combinations of types co we can only check if input type is a subclass of super type - input.canBeImplicitlyConvertedTo(superType) + input.canBeConvertedTo(superType) } } } @@ -483,12 +483,12 @@ class TypingResultSpec logger.trace(s"Checking supertype of: ${first.display} and ${second.display}") withClue(s"Input: ${first.display}; ${second.display};") { - first.canBeImplicitlyConvertedTo(first) shouldBe true - second.canBeImplicitlyConvertedTo(second) shouldBe true + first.canBeConvertedTo(first) shouldBe true + second.canBeConvertedTo(second) shouldBe true val superType = CommonSupertypeFinder.Default.commonSupertype(first, second) withClue(s"Supertype: ${superType.display};") { - first.canBeImplicitlyConvertedTo(superType) - second.canBeImplicitlyConvertedTo(superType) + first.canBeConvertedTo(superType) + second.canBeConvertedTo(superType) } } } diff --git a/designer/server/src/main/scala/pl/touk/nussknacker/ui/api/DictApiHttpService.scala b/designer/server/src/main/scala/pl/touk/nussknacker/ui/api/DictApiHttpService.scala index d43ad4b89b9..8a832701199 100644 --- a/designer/server/src/main/scala/pl/touk/nussknacker/ui/api/DictApiHttpService.scala +++ b/designer/server/src/main/scala/pl/touk/nussknacker/ui/api/DictApiHttpService.scala @@ -63,7 +63,7 @@ class DictApiHttpService( success( dictionaries .filter { case (id, definition) => - definition.valueType(id).canBeStrictSubclassOf(expectedType) + definition.valueType(id).canBeStrictlyConvertedTo(expectedType) } .map { case (id, _) => DictDto(id, id) } .toList diff --git a/engine/flink/components/base-tests/src/test/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/AggregatesSpec.scala b/engine/flink/components/base-tests/src/test/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/AggregatesSpec.scala index 12350236313..1a8a5e13686 100644 --- a/engine/flink/components/base-tests/src/test/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/AggregatesSpec.scala +++ b/engine/flink/components/base-tests/src/test/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/AggregatesSpec.scala @@ -74,8 +74,8 @@ class AggregatesSpec extends AnyFunSuite with TableDrivenPropertyChecks with Mat private def shouldBeInstanceOf(obj: Any, typ: TypingResult): Unit = { val typeFromInstance = Typed.fromInstance(obj) - val canBeSubclassCase = typeFromInstance.canBeImplicitlyConvertedTo(typ) - val typedObjectCase = typ.isInstanceOf[TypedObjectTypingResult] && typeFromInstance.canBeImplicitlyConvertedTo( + val canBeSubclassCase = typeFromInstance.canBeConvertedTo(typ) + val typedObjectCase = typ.isInstanceOf[TypedObjectTypingResult] && typeFromInstance.canBeConvertedTo( typ.asInstanceOf[TypedObjectTypingResult].runtimeObjType ) (canBeSubclassCase || typedObjectCase) shouldBe true diff --git a/engine/flink/components/base-unbounded/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/aggregates.scala b/engine/flink/components/base-unbounded/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/aggregates.scala index a9f883d1e6e..09d79139607 100644 --- a/engine/flink/components/base-unbounded/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/aggregates.scala +++ b/engine/flink/components/base-unbounded/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/aggregate/aggregates.scala @@ -190,7 +190,7 @@ object aggregates { override def result(finalAggregate: Aggregate): AnyRef = finalAggregate override def computeOutputType(input: typing.TypingResult): Validated[String, typing.TypingResult] = { - if (input.canBeImplicitlyConvertedTo(Typed[Boolean])) { + if (input.canBeConvertedTo(Typed[Boolean])) { Valid(Typed[Long]) } else { Invalid(s"Invalid aggregate type: ${input.display}, should be: ${Typed[Boolean].display}") @@ -239,7 +239,7 @@ object aggregates { override def computeOutputType(input: typing.TypingResult): Validated[String, typing.TypingResult] = { - if (!input.canBeImplicitlyConvertedTo(Typed[Number])) { + if (!input.canBeConvertedTo(Typed[Number])) { Invalid(s"Invalid aggregate type: ${input.display}, should be: ${Typed[Number].display}") } else { Valid(ForLargeFloatingNumbersOperation.promoteSingle(input)) @@ -353,7 +353,7 @@ object aggregates { ): Validated[String, TypedObjectTypingResult] = { input match { case TypedObjectTypingResult(inputFields, klass, _) - if inputFields.keySet == scalaFields.keySet && klass.canBeImplicitlyConvertedTo( + if inputFields.keySet == scalaFields.keySet && klass.canBeConvertedTo( Typed[java.util.Map[String, _]] ) => val validationRes = scalaFields @@ -439,7 +439,7 @@ object aggregates { trait MathAggregator { self: ReducingAggregator => override def computeOutputType(input: typing.TypingResult): Validated[String, typing.TypingResult] = { - if (input.canBeImplicitlyConvertedTo(Typed[Number])) { + if (input.canBeConvertedTo(Typed[Number])) { // In some cases type can be promoted to other class e.g. Byte is promoted to Int for sum Valid(promotionStrategy.promoteSingle(input)) } else { diff --git a/engine/flink/components/base/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/ForEachTransformer.scala b/engine/flink/components/base/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/ForEachTransformer.scala index 951be76ce26..e5f961a79df 100644 --- a/engine/flink/components/base/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/ForEachTransformer.scala +++ b/engine/flink/components/base/src/main/scala/pl/touk/nussknacker/engine/flink/util/transformer/ForEachTransformer.scala @@ -45,7 +45,7 @@ object ForEachTransformer extends CustomStreamTransformer with Serializable { private def returnType(elements: LazyParameter[util.Collection[AnyRef]]): typing.TypingResult = elements.returnType match { case tc: SingleTypingResult - if tc.runtimeObjType.canBeImplicitlyConvertedTo( + if tc.runtimeObjType.canBeConvertedTo( Typed[util.Collection[_]] ) && tc.runtimeObjType.params.nonEmpty => tc.runtimeObjType.params.head diff --git a/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/sink/TableTypeOutputValidator.scala b/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/sink/TableTypeOutputValidator.scala index 05f6b8cda9e..5b22fca0343 100644 --- a/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/sink/TableTypeOutputValidator.scala +++ b/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/sink/TableTypeOutputValidator.scala @@ -14,7 +14,7 @@ object TableTypeOutputValidator { val aligned = ToTableTypeSchemaBasedEncoder.alignTypingResult(actualType, expectedType) val expectedTypingResult = expectedType.toTypingResult - if (aligned.canBeImplicitlyConvertedTo(expectedTypingResult)) { + if (aligned.canBeConvertedTo(expectedTypingResult)) { Valid(()) } else { invalidNel( diff --git a/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/utils/ToTableTypeSchemaBasedEncoder.scala b/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/utils/ToTableTypeSchemaBasedEncoder.scala index 27ae00600c8..d0a584b49f4 100644 --- a/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/utils/ToTableTypeSchemaBasedEncoder.scala +++ b/engine/flink/components/table/src/main/scala/pl/touk/nussknacker/engine/flink/table/utils/ToTableTypeSchemaBasedEncoder.scala @@ -26,8 +26,7 @@ object ToTableTypeSchemaBasedEncoder { case (null, _) => null // We don't know what is the precise of decimal so we have to assume that it will fit the target type to not block the user - case (number: Number, _) - if Typed.typedClass(number.getClass).canBeImplicitlyConvertedTo(targetType.toTypingResult) => + case (number: Number, _) if Typed.typedClass(number.getClass).canBeConvertedTo(targetType.toTypingResult) => NumberUtils .convertNumberToTargetClass[Number](number, targetType.getDefaultConversion.asInstanceOf[Class[Number]]) case (_, rowType: RowType) => @@ -84,7 +83,7 @@ object ToTableTypeSchemaBasedEncoder { // We don't know what is the precision of decimal so we have to assume that it will fit the target type to not block the user case (typ: SingleTypingResult, _) if typ - .canBeImplicitlyConvertedTo(Typed[Number]) && typ.canBeImplicitlyConvertedTo(targetType.toTypingResult) => + .canBeConvertedTo(Typed[Number]) && typ.canBeConvertedTo(targetType.toTypingResult) => targetType.toTypingResult case (recordType: TypedObjectTypingResult, rowType: RowType) if Set[Class[_]](javaMapClass, rowClass).contains(recordType.runtimeObjType.klass) => @@ -106,10 +105,10 @@ object ToTableTypeSchemaBasedEncoder { case ( TypedObjectTypingResult(_, TypedClass(`javaMapClass`, keyType :: valueType :: Nil), _), multisetType: MultisetType - ) if valueType.canBeImplicitlyConvertedTo(Typed[Int]) => + ) if valueType.canBeConvertedTo(Typed[Int]) => alignMultisetType(keyType, multisetType) case (TypedClass(`javaMapClass`, keyType :: valueType :: Nil), multisetType: MultisetType) - if valueType.canBeImplicitlyConvertedTo(Typed[Int]) => + if valueType.canBeConvertedTo(Typed[Int]) => alignMultisetType(keyType, multisetType) case (TypedClass(`arrayClass`, elementType :: Nil), arrayType: ArrayType) => Typed.genericTypeClass(arrayClass, List(alignTypingResult(elementType, arrayType.getElementType))) diff --git a/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/DocumentationFunctions.scala b/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/DocumentationFunctions.scala index bcbc358fc7c..768f8f202a4 100644 --- a/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/DocumentationFunctions.scala +++ b/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/DocumentationFunctions.scala @@ -62,7 +62,7 @@ object DocumentationFunctions { (left.withoutValue, right.withoutValue) match { case (`intType`, `intType`) => intType.validNel case (`doubleType`, `doubleType`) => doubleType.validNel - case (l, r) if List(l, r).forall(_.canBeImplicitlyConvertedTo(numberType)) => + case (l, r) if List(l, r).forall(_.canBeConvertedTo(numberType)) => OtherError(s"Addition of ${l.display} and ${r.display} is not supported").invalidNel case (`stringType`, `stringType`) => stringType.validNel case _ => ArgumentTypeError.invalidNel @@ -110,7 +110,7 @@ object DocumentationFunctions { case Some(v) => v.validNel case None => OtherError("No field with given name").invalidNel } - case TypedObjectTypingResult(_, _, _) :: x :: Nil if x.canBeImplicitlyConvertedTo(stringType) => + case TypedObjectTypingResult(_, _, _) :: x :: Nil if x.canBeConvertedTo(stringType) => OtherError("Expected string with known value").invalidNel case _ => ArgumentTypeError.invalidNel diff --git a/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/ExampleFunctions.scala b/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/ExampleFunctions.scala index 723c0d2257b..8c998464dd1 100644 --- a/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/ExampleFunctions.scala +++ b/engine/flink/management/dev-model/src/main/scala/pl/touk/nussknacker/engine/management/sample/global/ExampleFunctions.scala @@ -147,7 +147,7 @@ object ExampleFunctions { override def computeResultType( arguments: List[TypingResult] ): ValidatedNel[GenericFunctionTypingError, TypingResult] = { - if (arguments.exists(!_.canBeImplicitlyConvertedTo(Typed[Number]))) return ArgumentTypeError.invalidNel + if (arguments.exists(!_.canBeConvertedTo(Typed[Number]))) return ArgumentTypeError.invalidNel arguments match { case t :: Nil => t.validNel case l :: r :: Nil => Typed.record(Map("left" -> l, "right" -> r)).validNel diff --git a/engine/lite/components/base/src/main/scala/pl/touk/nussknacker/engine/lite/components/ForEachTransformer.scala b/engine/lite/components/base/src/main/scala/pl/touk/nussknacker/engine/lite/components/ForEachTransformer.scala index a2f82110e22..3b8a47732dd 100644 --- a/engine/lite/components/base/src/main/scala/pl/touk/nussknacker/engine/lite/components/ForEachTransformer.scala +++ b/engine/lite/components/base/src/main/scala/pl/touk/nussknacker/engine/lite/components/ForEachTransformer.scala @@ -42,7 +42,7 @@ class ForEachTransformerComponent(elements: LazyParameter[java.util.Collection[A override def returnType: typing.TypingResult = { elements.returnType match { case tc: SingleTypingResult - if tc.runtimeObjType.canBeImplicitlyConvertedTo( + if tc.runtimeObjType.canBeConvertedTo( Typed[java.util.Collection[_]] ) && tc.runtimeObjType.params.nonEmpty => tc.runtimeObjType.params.head diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/compile/nodecompilation/FragmentParameterValidator.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/compile/nodecompilation/FragmentParameterValidator.scala index 01e37795330..5247cfd39f0 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/compile/nodecompilation/FragmentParameterValidator.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/compile/nodecompilation/FragmentParameterValidator.scala @@ -154,7 +154,7 @@ object FragmentParameterValidator { val dictValueType = dictDefinition.valueType(dictId) - if (dictValueType.canBeImplicitlyConvertedTo(fragmentParameterTypingResult)) { + if (dictValueType.canBeConvertedTo(fragmentParameterTypingResult)) { Valid(()) } else { invalidNel( diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/ClassDefinitionExtractor.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/ClassDefinitionExtractor.scala index d86ef54a602..865134301ee 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/ClassDefinitionExtractor.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/ClassDefinitionExtractor.scala @@ -141,7 +141,7 @@ class ClassDefinitionExtractor(settings: ClassExtractionSettings) extends LazyLo methodsForParams .find { case (_, method) => - methodsForParams.forall(mi => method.signature.result.canBeImplicitlyConvertedTo(mi._2.signature.result)) + methodsForParams.forall(mi => method.signature.result.canBeConvertedTo(mi._2.signature.result)) } .getOrElse(methodsForParams.minBy(_._2.signature.result.display)) } @@ -273,7 +273,7 @@ class ClassDefinitionExtractor(settings: ClassExtractionSettings) extends LazyLo ) reflectionBasedDefinition.result } - if (returnedResultType.canBeImplicitlyConvertedTo(returnedResultType)) { + if (returnedResultType.canBeConvertedTo(returnedResultType)) { returnedResultType } else { logger.warn( diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodDefinition.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodDefinition.scala index 452d5b64258..beac88237fb 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodDefinition.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodDefinition.scala @@ -35,15 +35,15 @@ sealed trait MethodDefinition { // Allow pass array as List argument because of array to list auto conversion: // pl.touk.nussknacker.engine.spel.internal.ArrayToListConverter case (tc @ TypedClass(klass, _), Parameter(_, y)) if klass.isArray => - tc.canBeImplicitlyConvertedTo(y) || Typed + tc.canBeConvertedTo(y) || Typed .genericTypeClass[java.util.List[_]](tc.params) - .canBeImplicitlyConvertedTo(y) - case (x, Parameter(_, y)) => x.canBeImplicitlyConvertedTo(y) + .canBeConvertedTo(y) + case (x, Parameter(_, y)) => x.canBeConvertedTo(y) } val checkVarArgs = methodTypeInfo.varArg match { case Some(Parameter(_, t)) => - arguments.drop(methodTypeInfo.noVarArgs.length).forall(_.canBeImplicitlyConvertedTo(t)) + arguments.drop(methodTypeInfo.noVarArgs.length).forall(_.canBeConvertedTo(t)) case None => arguments.length == methodTypeInfo.noVarArgs.length } @@ -96,7 +96,7 @@ case class FunctionalMethodDefinition( val typeCalculated = typeFunction(methodInvocationTarget, arguments).leftMap(_.map(errorConverter.convert)) typeCalculated.map { calculated => - if (!typesFromStaticMethodInfo.exists(calculated.canBeImplicitlyConvertedTo)) { + if (!typesFromStaticMethodInfo.exists(calculated.canBeConvertedTo)) { val expectedTypesString = typesFromStaticMethodInfo.map(_.display).mkString("(", ", ", ")") val argumentsString = arguments.map(_.display).mkString("(", ", ", ")") throw new AssertionError( diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodTypeInfoSubclassChecker.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodTypeInfoSubclassChecker.scala index 8a148911c10..a2a6f417800 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodTypeInfoSubclassChecker.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/definition/clazz/MethodTypeInfoSubclassChecker.scala @@ -12,7 +12,7 @@ object MethodTypeInfoSubclassChecker { val MethodTypeInfo(superclassNoVarArg, superclassVarArgOption, superclassResult) = superclassInfo val validatedVarArgs = (subclassVarArgOption, superclassVarArgOption) match { - case (Some(sub), Some(sup)) if sub.refClazz.canBeImplicitlyConvertedTo(sup.refClazz) => ().validNel + case (Some(sub), Some(sup)) if sub.refClazz.canBeConvertedTo(sup.refClazz) => ().validNel case (Some(sub), Some(sup)) => NotSubclassVarArgument(sub.refClazz, sup.refClazz).invalidNel case (Some(_), None) => BadVarArg.invalidNel case (None, Some(_)) => ().validNel @@ -38,7 +38,7 @@ object MethodTypeInfoSubclassChecker { ) val validatedNoVarArgs = zippedParameters.zipWithIndex .map { - case ((sub, sup), _) if sub.refClazz.canBeImplicitlyConvertedTo(sup.refClazz) => ().validNel + case ((sub, sup), _) if sub.refClazz.canBeConvertedTo(sup.refClazz) => ().validNel case ((sub, sup), i) => NotSubclassArgument(i + 1, sub.refClazz, sup.refClazz).invalidNel } .sequence @@ -46,7 +46,7 @@ object MethodTypeInfoSubclassChecker { val validatedResult = Validated.condNel( - subclassResult.canBeImplicitlyConvertedTo(superclassResult), + subclassResult.canBeConvertedTo(superclassResult), (), NotSubclassResult(subclassResult, superclassResult) ) diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/language/dictWithLabel/DictKeyWithLabelExpressionParser.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/language/dictWithLabel/DictKeyWithLabelExpressionParser.scala index 75ccd94f555..466f55602f2 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/language/dictWithLabel/DictKeyWithLabelExpressionParser.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/language/dictWithLabel/DictKeyWithLabelExpressionParser.scala @@ -70,11 +70,11 @@ object DictKeyWithLabelExpressionParser extends ExpressionParser { override def language: Language = languageId override def evaluate[T](ctx: Context, globals: Map[String, Any]): T = { - if (expectedType.canBeImplicitlyConvertedTo(Typed[Long])) { + if (expectedType.canBeConvertedTo(Typed[Long])) { key.toLong.asInstanceOf[T] - } else if (expectedType.canBeImplicitlyConvertedTo(Typed[Boolean])) { + } else if (expectedType.canBeConvertedTo(Typed[Boolean])) { key.toBoolean.asInstanceOf[T] - } else if (expectedType.canBeImplicitlyConvertedTo(Typed[String])) { + } else if (expectedType.canBeConvertedTo(Typed[String])) { key.asInstanceOf[T] } else { throw new IllegalStateException( diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSuggester.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSuggester.scala index a63782e2b9f..546dbfebac6 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSuggester.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSuggester.scala @@ -411,9 +411,9 @@ class SpelExpressionSuggester( private def determineIterableElementTypingResult(parent: TypingResult): TypingResult = { parent match { - case tc: SingleTypingResult if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Collection[_]]) => + case tc: SingleTypingResult if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Collection[_]]) => tc.runtimeObjType.params.headOption.getOrElse(Unknown) - case tc: SingleTypingResult if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Map[_, _]]) => + case tc: SingleTypingResult if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Map[_, _]]) => Typed.record( Map( "key" -> tc.runtimeObjType.params.headOption.getOrElse(Unknown), diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionValidator.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionValidator.scala index 6fc8764dafd..01cf733cd5f 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionValidator.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpressionValidator.scala @@ -18,8 +18,7 @@ class SpelExpressionValidator(typer: Typer) { val typedExpression = typer.typeExpression(expr, ctx) typedExpression.andThen { collected => collected.finalResult.typingResult match { - case a: TypingResult - if a.canBeImplicitlyConvertedTo(expectedType) || expectedType == Typed[SpelExpressionRepr] => + case a: TypingResult if a.canBeConvertedTo(expectedType) || expectedType == Typed[SpelExpressionRepr] => Valid(collected) case a: TypingResult => Invalid(NonEmptyList.of(ExpressionTypeError(expectedType, a))) diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/Typer.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/Typer.scala index 1c7aa1abe60..94398a81cd6 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/Typer.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/Typer.scala @@ -146,8 +146,8 @@ private[spel] class Typer( def withChildrenOfType[Parts: universe.TypeTag](result: TypingResult) = { val w = valid(result) withTypedChildren { - case list if list.forall(_.canBeImplicitlyConvertedTo(Typed.fromDetailedType[Parts])) => w - case _ => w.tell(List(PartTypeError)) + case list if list.forall(_.canBeConvertedTo(Typed.fromDetailedType[Parts])) => w + case _ => w.tell(List(PartTypeError)) } } @@ -198,7 +198,7 @@ private[spel] class Typer( case (ref: PropertyOrFieldReference) :: Nil => typeFieldNameReferenceOnRecord(ref.getName, record) case _ => typeFieldNameReferenceOnRecord(indexString, record) } - case indexKey :: Nil if indexKey.canBeImplicitlyConvertedTo(Typed[String]) => + case indexKey :: Nil if indexKey.canBeConvertedTo(Typed[String]) => if (dynamicPropertyAccessAllowed) valid(Unknown) else invalid(DynamicPropertyAccessError) case _ :: Nil => indexer.children match { @@ -356,8 +356,7 @@ private[spel] class Typer( case e: OpMinus => withTypedChildren { - case left :: right :: Nil - if left.canBeImplicitlyConvertedTo(Typed[Number]) && right.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: right :: Nil if left.canBeConvertedTo(Typed[Number]) && right.canBeConvertedTo(Typed[Number]) => val fallback = NumberTypesPromotionStrategy.ForMathOperation.promote(left, right) operationOnTypesValue[Number, Number, Number](left, right, fallback)((n1, n2) => Valid(MathUtils.minus(n1, n2)) @@ -366,7 +365,7 @@ private[spel] class Typer( invalid(OperatorNonNumericError(e.getOperatorName, left)) case left :: right :: Nil => invalid(OperatorMismatchTypeError(e.getOperatorName, left, right)) - case left :: Nil if left.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: Nil if left.canBeConvertedTo(Typed[Number]) => val resultType = left.withoutValue val result = operationOnTypesValue[Number, Number](left)(MathUtils.negate).getOrElse(resultType) valid(result) @@ -396,20 +395,18 @@ private[spel] class Typer( withTypedChildren { case left :: right :: Nil if left == Unknown || right == Unknown => valid(Unknown) - case left :: right :: Nil - if left.canBeImplicitlyConvertedTo(Typed[String]) || right.canBeImplicitlyConvertedTo(Typed[String]) => + case left :: right :: Nil if left.canBeConvertedTo(Typed[String]) || right.canBeConvertedTo(Typed[String]) => operationOnTypesValue[Any, Any, String](left, right, Typed[String])((l, r) => Valid(l.toString + r.toString) ) - case left :: right :: Nil - if left.canBeImplicitlyConvertedTo(Typed[Number]) && right.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: right :: Nil if left.canBeConvertedTo(Typed[Number]) && right.canBeConvertedTo(Typed[Number]) => val fallback = NumberTypesPromotionStrategy.ForMathOperation.promote(left, right) operationOnTypesValue[Number, Number, Number](left, right, fallback)((n1, n2) => Valid(MathUtils.plus(n1, n2)) ) case left :: right :: Nil => invalid(OperatorMismatchTypeError(e.getOperatorName, left, right)) - case left :: Nil if left.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: Nil if left.canBeConvertedTo(Typed[Number]) => valid(left) case left :: Nil => invalid(OperatorNonNumericError(e.getOperatorName, left)) @@ -451,7 +448,7 @@ private[spel] class Typer( elementType <- extractIterativeType(iterateType) selectionType = resolveSelectionTypingResult(e, iterateType, elementType) result <- typeChildren(validationContext, node, current.pushOnStack(elementType)) { - case result :: Nil if result.canBeImplicitlyConvertedTo(Typed[Boolean]) => + case result :: Nil if result.canBeConvertedTo(Typed[Boolean]) => valid(selectionType) case other => invalid(IllegalSelectionTypeError(other), selectionType) @@ -462,7 +459,7 @@ private[spel] class Typer( case condition :: onTrue :: onFalse :: Nil => for { _ <- Option(condition) - .filter(_.canBeImplicitlyConvertedTo(Typed[Boolean])) + .filter(_.canBeConvertedTo(Typed[Boolean])) .map(valid) .getOrElse(invalid(TernaryOperatorNotBooleanError(condition))) } yield CommonSupertypeFinder.Default.commonSupertype(onTrue, onFalse) @@ -523,10 +520,10 @@ private[spel] class Typer( // as properly determining it would require evaluating the selection expression for each element (likely working on the AST) parentType match { case tc: SingleTypingResult - if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Collection[_]]) || + if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Collection[_]]) || tc.runtimeObjType.klass.isArray => tc.withoutValue - case tc: SingleTypingResult if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Map[_, _]]) => + case tc: SingleTypingResult if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Map[_, _]]) => Typed.record(Map.empty) case _ => parentType @@ -578,8 +575,7 @@ private[spel] class Typer( op: Option[(Number, Number) => Validated[ExpressionParseError, Any]] )(implicit numberPromotionStrategy: NumberTypesPromotionStrategy): TypingR[CollectedTypingResult] = { typeChildren(validationContext, node, current) { - case left :: right :: Nil - if left.canBeImplicitlyConvertedTo(Typed[Number]) && right.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: right :: Nil if left.canBeConvertedTo(Typed[Number]) && right.canBeConvertedTo(Typed[Number]) => val fallback = numberPromotionStrategy.promote(left, right) op .map(operationOnTypesValue[Number, Number, Any](left, right, fallback)(_)) @@ -598,7 +594,7 @@ private[spel] class Typer( current: TypingContext )(op: Number => Any): TypingR[CollectedTypingResult] = { typeChildren(validationContext, node, current) { - case left :: Nil if left.canBeImplicitlyConvertedTo(Typed[Number]) => + case left :: Nil if left.canBeConvertedTo(Typed[Number]) => val result = operationOnTypesValue[Number, Any](left)(op).getOrElse(left.withoutValue) valid(result) case left :: Nil => @@ -694,10 +690,10 @@ private[spel] class Typer( private def extractIterativeType(parent: TypingResult): TypingR[TypingResult] = parent match { case tc: SingleTypingResult - if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Collection[_]]) || + if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Collection[_]]) || tc.runtimeObjType.klass.isArray => valid(tc.runtimeObjType.params.headOption.getOrElse(Unknown)) - case tc: SingleTypingResult if tc.runtimeObjType.canBeImplicitlyConvertedTo(Typed[java.util.Map[_, _]]) => + case tc: SingleTypingResult if tc.runtimeObjType.canBeConvertedTo(Typed[java.util.Map[_, _]]) => valid( Typed.record( Map( diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/typer/MethodReferenceTyper.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/typer/MethodReferenceTyper.scala index 9926b337e95..08cb6e00379 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/typer/MethodReferenceTyper.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/typer/MethodReferenceTyper.scala @@ -62,7 +62,7 @@ class MethodReferenceTyper(classDefinitionSet: ClassDefinitionSet, methodExecuti )(implicit reference: MethodReference): Either[Option[ExpressionParseError], NonEmptyList[MethodDefinition]] = { def displayableType = clazzDefinitions.map(k => k.clazzName).map(_.display).toList.mkString(", ") - def isClass = clazzDefinitions.map(k => k.clazzName).exists(_.canBeImplicitlyConvertedTo(Typed[Class[_]])) + def isClass = clazzDefinitions.map(k => k.clazzName).exists(_.canBeConvertedTo(Typed[Class[_]])) val clazzMethods = if (reference.isStatic) clazzDefinitions.toList.flatMap(_.staticMethods.get(reference.methodName).toList.flatten) diff --git a/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/collection.scala b/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/collection.scala index 0858fe97465..aaaab391009 100644 --- a/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/collection.scala +++ b/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/collection.scala @@ -357,8 +357,8 @@ object CollectionUtils { case _ if firstComponentType.withoutValue == secondComponentType.withoutValue => listType.copy(params = firstComponentType.withoutValue :: Nil) case _ - if firstComponentType.canBeImplicitlyConvertedTo(numberType) && secondComponentType - .canBeImplicitlyConvertedTo(numberType) => + if firstComponentType.canBeConvertedTo(numberType) && secondComponentType + .canBeConvertedTo(numberType) => Typed.genericTypeClass(fClass, List(numberType)) case _ => listType.copy(params = Unknown :: Nil) } diff --git a/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/numeric.scala b/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/numeric.scala index bc6d1d2a1f5..880a216ed77 100644 --- a/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/numeric.scala +++ b/utils/default-helpers/src/main/scala/pl/touk/nussknacker/engine/util/functions/numeric.scala @@ -129,7 +129,7 @@ object NumericUtils { override def computeResultType( arguments: List[typing.TypingResult] ): ValidatedNel[GenericFunctionTypingError, typing.TypingResult] = { - if (arguments.head.canBeImplicitlyConvertedTo(Typed[Number])) arguments.head.withoutValue.validNel + if (arguments.head.canBeConvertedTo(Typed[Number])) arguments.head.withoutValue.validNel else Typed[Number].validNel } diff --git a/utils/json-utils/src/main/scala/pl/touk/nussknacker/engine/json/encode/JsonSchemaOutputValidator.scala b/utils/json-utils/src/main/scala/pl/touk/nussknacker/engine/json/encode/JsonSchemaOutputValidator.scala index 1219aacde4a..d15d678e89a 100644 --- a/utils/json-utils/src/main/scala/pl/touk/nussknacker/engine/json/encode/JsonSchemaOutputValidator.scala +++ b/utils/json-utils/src/main/scala/pl/touk/nussknacker/engine/json/encode/JsonSchemaOutputValidator.scala @@ -370,7 +370,7 @@ class JsonSchemaOutputValidator(validationMode: ValidationMode) extends LazyLogg case (TypedClass(_, Nil), TypedClass(_, Nil)) => invalid(typingResult, schema, rootSchema, path) case _ => condNel( - typingResult.canBeImplicitlyConvertedTo(schemaAsTypedResult), + typingResult.canBeConvertedTo(schemaAsTypedResult), (), OutputValidatorTypeError(path, typingResult, JsonSchemaExpected(schema, rootSchema)) ) diff --git a/utils/schemed-kafka-components-utils/src/main/scala/pl/touk/nussknacker/engine/schemedkafka/encode/AvroSchemaOutputValidator.scala b/utils/schemed-kafka-components-utils/src/main/scala/pl/touk/nussknacker/engine/schemedkafka/encode/AvroSchemaOutputValidator.scala index 48292b5697e..38106336172 100644 --- a/utils/schemed-kafka-components-utils/src/main/scala/pl/touk/nussknacker/engine/schemedkafka/encode/AvroSchemaOutputValidator.scala +++ b/utils/schemed-kafka-components-utils/src/main/scala/pl/touk/nussknacker/engine/schemedkafka/encode/AvroSchemaOutputValidator.scala @@ -153,7 +153,7 @@ class AvroSchemaOutputValidator(validationMode: ValidationMode) extends LazyLogg case _ @TypedClass(klass, key :: value :: Nil) if isMap(klass) => // Map keys are assumed to be strings: https://avro.apache.org/docs/current/spec.html#Maps condNel( - key.canBeImplicitlyConvertedTo(Typed.apply[java.lang.String]), + key.canBeConvertedTo(Typed.apply[java.lang.String]), (), typeError(typingResult, schema, path) ).andThen(_ => validateTypingResult(value, schema.getValueType, buildPath("*", path, useIndexer = true)))