In an abstraction /\a\x:a.e the type variable a can appear in the type of a term-variable binder x. In contrast x can't appear in the type of another binder. Coercion binders behave exactly like term binders in this way, and quite unlike type binders.

More seeriously, we don't have a decent way to handle superclass equalities.

The last problem is the one that triggered this note, and needs a bit more explanation. Consider

But Core doesn't (currently) have a let-binding form that binds a coercion
variable, and whose right-hand side is a term (in this example, a case expression)
rather than a literal coercion! So the current plan is to generate this
instead:

g = /\ab. \(d:C a b).
case d of { MkC eq _ _ ->
in xs |> [eq] }

This non-uniformity of equality and dictionary evidence
is extremely awkward in the desugarer. Moreover, it means that we can't abstract
the superclass selector; we'd really like to have:

g = /\ab. \(d:C a b).
let (eq : F a ~ b) = sc_sel1 d
in xs |> [eq]

And it interacts poorly with the class-op rules that GHC uses to simplify
dictinary selectors. Imagine the call

Var can be a type variable, coercion variable, or term variable. You can tell which with a dynamic test (e.g. isId :: Var -> Bool).

Lam is used for type abstractions, coercion abstractions, and value abstractions. The Var can tell you which.

Type applications (in a term) look like (App f (Type t)). The (Type t) part must literally appear there, with no intervening junk. This is not statically enforced, but it turns out to be much more convenient than having a constructor TyApp CoreExpr Type.