Probando una afirmación de que algo no debe compilar

El problema

Cuando trabajo con bibliotecas que admiten la programación a nivel de tipo, a menudo me encuentro escribiendo comentarios como los siguientes (deun ejemplo presentado porPaul Snively en Strange Loop 2012):

// But these invalid sequences don't compile:
// isValid(_3 :: _1 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: _5 :: HNil)
// isValid(_3 :: _4 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: HNil)

O esto, desdeun ejemplo en elInforme repositorio:

/**
 * If we wanted to confirm that the list uniquely contains `Foo` or any
 * subtype of `Foo`, we could first use `unifySubtypes` to upcast any
 * subtypes of `Foo` in the list to `Foo`.
 *
 * The following would not compile, for example:
 */
 //stuff.unifySubtypes[Foo].unique[Foo]

Esta es una manera muy aproximada de indicar algún hecho sobre el comportamiento de estos métodos, y podríamos imaginar querer hacer estas afirmaciones más formales, para pruebas de unidad o de regresión, etc.

Para dar un ejemplo concreto de por qué esto podría ser útil en el contexto de una biblioteca como Shapeless, hace unos días escribí lo siguiente como un primer intento rápido de respuesta aesta pregunta:

import shapeless._

implicit class Uniqueable[L <: HList](l: L) {
  def unique[A](implicit ev: FilterAux[L, A, A :: HNil]) = ev(l).head
}

Donde la intención es que esto compile:

('a' :: 'b :: HNil).unique[Char]

Si bien esto no va a:

('a' :: 'b' :: HNil).unique[Char]

Me sorprendió descubrir que esta implementación de un nivel de tipounique paraHList no funcionó, porque Shapeless felizmente encontraría unFilterAux Ejemplo en este último caso. En otras palabras, lo siguiente se compilaría, aunque probablemente esperaría que no:

implicitly[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]

En este caso, lo que estaba viendo eraun insecto—O al menos algo de error — yya ha sido arreglado.

De manera más general, podemos imaginar querer verificar el tipo de invariante que estaba implícito en mis expectativas sobre cómoFilterAux debería trabaje con algo como una prueba de unidad, por extraño que parezca hablar de probar código de tipo de tipo como este, con todos los debates recientes sobre el mérito relativo de los tiposcontra pruebas

Mi pregunta

El problema es que no conozco ningún tipo de marco de prueba (para ninguna plataforma) que permita al programador afirmar que algo no debecompilar.

Un enfoque que puedo imaginar para elFilterAux caso sería utilizar el viejotruco implícito-argumento-con-nulo-predeterminado:

def assertNoInstanceOf[T](implicit instance: T = null) = assert(instance == null)

Lo que le permitiría escribir lo siguiente en su prueba de unidad:

assertNoInstanceOf[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]

Sin embargo, lo siguiente sería mucho más conveniente y expresivo:

assertDoesntCompile(('a' :: 'b' :: HNil).unique[Char])

Quiero esto. Mi pregunta es si alguien sabe de alguna biblioteca o marco de prueba que admita algo remotamente parecido, idealmente para Scala, pero me conformaré con cualquier cosa.

Respuestas a la pregunta(5)

Su respuesta a la pregunta