こんな感じで考えるのを辞めた

object ttest {

  trait TType
  case class TFloat() extends TType
  case class TInt() extends TType
  case class TNone() extends TType
  case class TStr() extends TType
  case class TFun(prms:List[TType],rc:TType) extends TType
  abstract class E(t:TType)
  case class EId(s:String) extends E(TStr())
  case class ECast(t:TType, a:T) extends E(t)
  case class EInt(t:TType, a:scala.Int) extends E(t)
  case class EFloat(t:TType, a:Double) extends E(t)
  case class ECall(t:TType, f:T, a:List[T]) extends E(t)

  def main(argv:Array[String]) {
    println(f(ECall(TNone(),EId("add"),List(EFloat(TFloat(),1),EInt(TInt(),2)))))
    println(f(ECall(TNone(),EId("add"),List(EInt(TInt(),1),EInt(TInt(),2)))))
    println(f(ECall(TNone(),EId("add"), List(ECall(TNone(),EId("add"),List(EFloat(TFloat(),1),EInt(TInt(),1))),EInt(TInt(),2)))))
  }
  
  def f(e:E):E = e match {
    case ECast(t,a) => ECast(t, f(a))
	case EInt(t,i) => EInt(TInt(), i)
	case EFloat(t,i) => EFloat(TFloat(), i)
	case ECall(t,id,xs) => ECall(t,id, xs.map(f))
  }
  // 関数定義表

  var functions = Map(
    "add"->List(
	  TFun(List(TInt(),TInt()),TInt()),
      TFun(List(TStr(),TStr()),TStr()),
      TFun(List(TFloat(),TFloat()),TFloat())
	  )
  )

  // 暗黙の型変換の表
  var implicitConversions = Map (
    (TInt(),TStr()) -> (a:TInt)=>ECast(TStr(),a),
    (TFloat(),TStr()) -> (a:TFloat)=>ECast(TStr(),a),
    (TFloat(),TInt()) -> (a:TFloat)=>ECast(TInt(),a)
  )
}

オーバーロードの関数の表があって、
暗黙の型変換の表があって、変換関数があって、後は、表見てあったら変換関数を噛ませると良いです。
とくに、C言語では、オーバーロード出来る必要ないので、単純に、変換出来たら良い。
後サイズとか持てば良いはず。