Tipo di ritorno statico di macro Scala

Quindi ho questa macro:

import language.experimental.macros import scala.reflect.macros.Context class Foo class Bar extends Foo { def launchMissiles = "launching" } object FooExample { def foo: Foo = macro foo_impl def foo_impl(c: Context): c.Expr[Foo] = c.Expr[Foo](c.universe.reify(new Bar).tree) } 

Ho detto tre volte che voglio foo per restituire un Foo , eppure posso fare quanto segue (in 2.10.0-RC3):

 scala> FooExample.foo res0: Bar = [email protected] scala> res0.launchMissiles res1: String = launching 

La stessa cosa accade se rimuovo i parametri del tipo su c.Expr . Se voglio davvero assicurarmi che chi sta chiamando foo non possa vedere che sta ricevendo una Bar , devo aggiungere un’ascrizione di tipo nell’albero stesso.

Questo in realtà è piuttosto grande: significa ad esempio che posso puntare una macro su uno schema di qualche tipo e creare una sottoclass anonima di alcune classi di Vocabulary con metodi membro che rappresentano termini nel vocabolario, e questi saranno disponibili sull’object restituito.

Mi piacerebbe capire esattamente cosa sto facendo, però, quindi ho un paio di domande. Innanzitutto, qual è il tipo di ritorno per il metodo foo realtà? È solo disponibile per la documentazione (facoltativa)? Vincola chiaramente il tipo di ritorno (ad esempio, non posso cambiarlo in Int in questo caso), e se lo rimuovo completamente ottengo un errore come questo:

 scala> FooExample.foo :8: error: type mismatch; found : Bar required: Nothing FooExample.foo ^ 

Ma posso cambiarlo in Any e ottenere sempre una Bar tipizzata staticamente quando chiamo foo .

Secondo, questo comportamento è specificato da qualche parte? Questo mi sembra un insieme abbastanza elementare di problemi, ma non sono stato in grado di cercare una spiegazione o una discussione chiara.

Questo comportamento è sottodescritto ma inteso, sebbene possa sembrare confuso. Abbiamo in programma di elaborare il ruolo del tipo restituito nelle macro firme, ma al momento sento che la flessibilità è una buona cosa da avere.

Anche a volte il comportamento è incoerente, ad esempio quando la macro viene catturata nel mezzo dell’inferenza di tipo, verrà utilizzata la sua firma statica (ad es. Foo nell’esempio), non il tipo di espansione effettiva. Questo perché l’espansione delle macro è intenzionalmente ritardata fino a quando non viene eseguita l’inferenza di tipo (in modo che le implementazioni macro possano vedere i tipi dedotti, non i tipi vars). Questo è un trade-off e non è necessariamente il migliore, quindi abbiamo intenzione di rivederlo presto: https://issues.scala-lang.org/browse/SI-6755 .

Un altro problema in questo reparto è con macro implicite. Quando il tipo restituito di una macro implicita è generico e deve essere dedotto dal tipo richiesto di un valore implicito, accadono cose brutte. Ciò rende attualmente imansible l’utilizzo di macro per generare tag di tipo: https://issues.scala-lang.org/browse/SI-5923 .