Testen einer Behauptung, dass etwas nicht kompiliert werden darf

Das Problem

Wenn ich mit Bibliotheken arbeite, die die Programmierung auf Typebene unterstützen, schreibe ich häufig Kommentare wie die folgenden (vonein Beispiel präsentiert vonPaul Snively auf der 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)

Oder das ausein Beispiel in demFormlos Repository:

/**
 * 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]

Dies ist eine sehr grobe Methode, um Fakten über das Verhalten dieser Methoden anzuzeigen, und wir könnten uns vorstellen, diese Behauptungen formeller zu formulieren - für Einheiten- oder Regressionstests usw.

Um ein konkretes Beispiel dafür zu geben, warum dies im Kontext einer Bibliothek wie Shapeless nützlich sein könnte, habe ich vor ein paar Tagen als ersten Versuch, eine Antwort auf diese Frage zu finden, Folgendes geschriebendiese Frage:

import shapeless._

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

Wo die Absicht ist, dass dies kompiliert wird:

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

Dies wird zwar nicht:

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

Ich war überrascht, dass diese Implementierung eine Typ-Ebene hatunique zumHList hat nicht funktioniert, weil Shapeless gerne einen finden würdeFilterAux Beispiel im letzteren Fall. Mit anderen Worten, das Folgende würde kompiliert, obwohl Sie es wahrscheinlich nicht erwarten würden:

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

In diesem Fall war das, was ich sahein Käfer- oder zumindest etwas Fehlerhaftes - und eswurde seitdem behoben.

Ganz allgemein können wir uns vorstellen, die Art der Invariante überprüfen zu wollen, die in meinen Erwartungen dahingehend impliziert war, wieFilterAux sollte Arbeiten Sie mit so etwas wie einem Komponententest - so komisch es auch klingen mag, wenn Sie über das Testen von Code auf Typebene mit all den jüngsten Debatten über den relativen Wert von Typen sprechengegen Tests.

Meine Frage

Das Problem ist, dass ich keine Art von Test-Framework (für jede Plattform) kenne, mit dem der Programmierer behaupten kann, dass etwas nicht sein darfkompilieren.

Ein Ansatz, den ich mir für das vorstellen kannFilterAux Fall wäre, die alten zu verwendenimplizites-argument-mit-null-default-trick:

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

Womit Sie in Ihrem Unit-Test Folgendes schreiben könnten:

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

Das Folgende wäre jedoch um einiges praktischer und aussagekräftiger:

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

Ich will das. Meine Frage ist, ob irgendjemand eine Testbibliothek oder ein Framework kennt, die bzw. das so etwas remote unterstützt - ideal für Scala, aber ich werde mich mit allem zufrieden geben.

Antworten auf die Frage(5)

Ihre Antwort auf die Frage