[Git][ghc/ghc][master] Deal with 'noSpec' in 'coreExprToPmLit'
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: e8a196c6 by sheaf at 2026-04-16T13:31:19-04:00 Deal with 'noSpec' in 'coreExprToPmLit' This commit makes two separate changes relating to 'GHC.HsToCore.Pmc.Solver.Types.coreExprAsPmLit': 1. Commit 7124e4ad mistakenly marked deferred errors as non-canonical, which led to the introduction of 'nospec' wrappers in the generated Core. This reverts that accident by declaring deferred errors as being canonical, avoiding spurious 'nospec' wrapping. 2. Look through magic identity-like Ids such as 'nospec', 'inline' and 'lazy' in 'coreExprAsPmLit', just like Core Prep does. There might genuinely be incoherent evidence, but that shouldn't obstruct the pattern match checker. See test T27124a. Fixes #25926 #27124 ------------------------- Metric Decrease: T3294 ------------------------- - - - - - 11 changed files: - + changelog.d/T27124.md - compiler/GHC/CoreToStg/Prep.hs - compiler/GHC/HsToCore/Pmc/Solver/Types.hs - compiler/GHC/Tc/Errors.hs - + testsuite/tests/overloadedstrings/should_fail/T25926.hs - + testsuite/tests/overloadedstrings/should_fail/T25926.stderr - + testsuite/tests/overloadedstrings/should_fail/T27124.hs - + testsuite/tests/overloadedstrings/should_fail/T27124.stderr - + testsuite/tests/overloadedstrings/should_fail/all.T - + testsuite/tests/overloadedstrings/should_run/T27124a.hs - testsuite/tests/overloadedstrings/should_run/all.T Changes: ===================================== changelog.d/T27124.md ===================================== @@ -0,0 +1,10 @@ +section: compiler +issues: #25926 #27124 +mrs: !15895 +synopsis: + Fix "failed to detect OverLit" panic in the pattern-match checker. +description: + Fixed an issue in which overloaded literals (e.g. numeric literals, overloaded + strings with -XOverloadedStrings, overloaded lists, etc) could cause a GHC + crash when using -fdefer-type-errors, with an error message of the form + "failed to detect OverLit". ===================================== compiler/GHC/CoreToStg/Prep.hs ===================================== @@ -1055,6 +1055,9 @@ cpeApp top_env expr || f `hasKey` nospecIdKey -- Replace (nospec a) with a -- See Note [nospecId magic] in GHC.Types.Id.Make + -- NB: keep this in sync with GHC.HsToCore.Pmc.Solver.Types.coreExprAsPmLit, + -- as that also needs to see through these magic Ids. + -- Consider the code: -- -- lazy (f x) y ===================================== compiler/GHC/HsToCore/Pmc/Solver/Types.hs ===================================== @@ -694,6 +694,15 @@ coreExprAsPmLit :: CoreExpr -> Maybe PmLit coreExprAsPmLit (Tick _t e) = coreExprAsPmLit e coreExprAsPmLit (Lit l) = literalToPmLit (literalType l) l coreExprAsPmLit e = case collectArgs e of + + -- Look through nospec, noinline and lazy, which are only eliminated by Core Prep. + -- See Note [coreExprAsPmLit and nospec] + (Var x, Type _ : inner : rest_args) + | x `hasKey` nospecIdKey + || x `hasKey` noinlineIdKey + || x `hasKey` lazyIdKey + -> coreExprAsPmLit (mkApps inner rest_args) + (Var x, [Lit l]) | Just dc <- isDataConWorkId_maybe x , dc `elem` [intDataCon, wordDataCon, charDataCon, floatDataCon, doubleDataCon] @@ -834,6 +843,34 @@ with large exponents case. This will return a `PmLitOverRat` literal. Which is then passed to overloadPmLit which simply returns it as-is since it's already overloaded. +Note [coreExprAsPmLit and nospec] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For coverage checking, we need to analyse overloaded literal patterns to figure +out which literals they correspond to; this is what 'coreExprAsPmLit' does. +For example, the literal pattern "fromString" (with -XOverloadedStrings) +will turn into an equality check against the **expression** + + fromString @T $dFromString "hello"# + +and 'coreExprAsPmLit' recovers the string by taking apart this application. + +However, when $dFromString is non-canonical (e.g. when an INCOHERENT +instance was discarded during resolution of the typeclass constraint, or when +the dictionary comes from 'withDict'), the desugarer wraps 'fromString' in +'nospec' (as per Note [nospecId magic] in GHC.Types.Id.Make and +Note [Desugaring non-canonical evidence] in GHC.HsToCore.Expr): + + nospec @(IsString a => String -> Maybe a) fromString @T $dFromString "hello"# + +(For a full example, see test case T27124a.) + +The 'nospec' mechanism only exists for the specialiser; it should be transparent +to everything else. 'coreExprAsPmLit' must thus look through the 'nospec' +application in order obtain the string "hello". If it doesn't, we can't do +pattern match checking (in fact GHC.HsToCore.Pmc.Desugar.desugarPat is liable +to crash!). + +The same reasoning applies to `noinline` and `lazy`. -} instance Outputable PmLitValue where ===================================== compiler/GHC/Tc/Errors.hs ===================================== @@ -1360,11 +1360,11 @@ addDeferredBinding ctxt supp hints msg (EI { ei_evdest = Just dest ; case dest of EvVarDest evar - -> addTcEvBind ev_binds_var $ mkWantedEvBind evar EvNonCanonical err_tm + -> addTcEvBind ev_binds_var $ mkWantedEvBind evar EvCanonical err_tm HoleDest hole -> do { -- See Note [Deferred errors for coercion holes] let co_var = coHoleCoVar hole - ; addTcEvBind ev_binds_var $ mkWantedEvBind co_var EvNonCanonical err_tm + ; addTcEvBind ev_binds_var $ mkWantedEvBind co_var EvCanonical err_tm ; fillCoercionHole hole (CPH { cph_co = mkCoVarCo co_var , cph_holes = emptyCoHoleSet }) } } addDeferredBinding _ _ _ _ _ = return () -- Do not set any evidence for Given ===================================== testsuite/tests/overloadedstrings/should_fail/T25926.hs ===================================== @@ -0,0 +1,4 @@ +module T25926 where + +f () 0 = () +f 'a' _ = () ===================================== testsuite/tests/overloadedstrings/should_fail/T25926.stderr ===================================== @@ -0,0 +1,5 @@ +T25926.hs:4:3: warning: [GHC-83865] [-Wdeferred-type-errors (in -Wdefault)] + • Couldn't match expected type ‘()’ with actual type ‘Char’ + • In the pattern: 'a' + In an equation for ‘f’: f 'a' _ = () + ===================================== testsuite/tests/overloadedstrings/should_fail/T27124.hs ===================================== @@ -0,0 +1,9 @@ +{-# LANGUAGE OverloadedStrings #-} + +module T27124 where + +foo :: [String] -> Bool +foo "HI" = True +foo _ = False + +main = pure () ===================================== testsuite/tests/overloadedstrings/should_fail/T27124.stderr ===================================== @@ -0,0 +1,6 @@ +T27124.hs:6:5: warning: [GHC-18872] [-Wdeferred-type-errors (in -Wdefault)] + • Couldn't match type ‘[Char]’ with ‘Char’ + arising from the literal ‘"HI"’ + • In the pattern: "HI" + In an equation for ‘foo’: foo "HI" = True + ===================================== testsuite/tests/overloadedstrings/should_fail/all.T ===================================== @@ -0,0 +1,2 @@ +test('T25926', normal, compile, ['-fdefer-type-errors']) +test('T27124', normal, compile, ['-fdefer-type-errors']) ===================================== testsuite/tests/overloadedstrings/should_run/T27124a.hs ===================================== @@ -0,0 +1,23 @@ +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverloadedStrings #-} + +module T27124a where + +import Data.String (IsString(..)) + +newtype Wrap a = Wrap a deriving (Eq, Show) + +instance IsString a => IsString (Wrap a) where + fromString = Wrap . fromString + +instance {-# INCOHERENT #-} IsString (Wrap Bool) where + fromString _ = Wrap False + +f :: (Eq a, IsString a) => Wrap a -> Bool +f "hello" = True +f _ = False + +main :: IO () +main = do + print (f (Wrap ("hello" :: String))) + print (f (Wrap ("world" :: String))) ===================================== testsuite/tests/overloadedstrings/should_run/all.T ===================================== @@ -1 +1,2 @@ test('overloadedstringsrun01', normal, compile_and_run, ['']) +test('T27124a', normal, compile, ['-fno-specialise-incoherents']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e8a196c65cee32f06c3d99b74af33457... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e8a196c65cee32f06c3d99b74af33457... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)