Opened 13 months ago

Last modified 9 months ago

#15863 new bug

Splcing a type class method selects the wrong instance

Reported by: mpickering Owned by:
Priority: normal Milestone:
Component: Template Haskell Version: 8.6.1
Keywords: TypedTemplateHaskell Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Consider these 4 modules as concocted by Csongor.

The wrong instance is selected when you splice in B.me into D.

https://gist.github.com/mpickering/959a95525647802414ab50e8e6ed490c

module A where

class C a where
  foo :: a -> String

instance C Int where
foo _ = "int"
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module B where

import A

import Language.Haskell.TH

instance C a => C [a] where
  foo _ = "list"

me :: Q (TExp ([Int] -> String))
me = [|| foo ||]
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module C where

import A

import Language.Haskell.TH

instance {-# OVERLAPPING #-} C [Int] where
foo _ = "list2"
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module D where

import A
import B
import C

main2 = $$(me) [1 :: Int]
>>> main2
"list2"

In B, B.me is created by quoting foo. B.me :: Q (TExp ([Int] -> String)) so in order to type check this quote we need to solve the instance C [Int] which we should do by using the instance defined in B (and A).

In module C we define a different overlapping instance (note that this could be in a completely different library not under our control).

When we then splice B.me into D, the instance from C is used and can be witnessed by printing main2 which shows "list2" rather than "list" as expected.

This is a symptom of the fact that the renamed rather than the typechecked AST is serialised I think.

Change History (3)

comment:1 Changed 10 months ago by mpickering

Keywords: TypedTemplateHaskell added

comment:2 Changed 10 months ago by goldfire

Component: CompilerTemplate Haskell

comment:3 Changed 9 months ago by Marge Bot <ben+marge-bot@…>

In a48753b/ghc:

Capture and simplify constraints arising from running typed splices

This fixes a regression caused by #15471 where splicing in a trivial
program such as `[|| return () ||]` would fail as the dictionary for
`return` would never get bound in the module containing the splice.

Arguably this is symptomatic of a major problem affecting TTH where we
serialise renamed asts and then retype check them. The reference to the
dictionary should be fully determined at the quote site so that splicing
doesn't have to solve any implicits at all. It's a coincidence this
works due to coherence but see #15863 and #15865 for examples where
things do go very wrong.

Fixes #16195
Note: See TracTickets for help on using tickets.