diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2020-02-07 15:26:44 +0000 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-02-28 22:03:23 -0500 |
commit | 66f5d6d634698ce054a9b9ce0c53ce9682f6f042 (patch) | |
tree | 24225b89347cb0f32cff1f3921d71305f5fbdaab | |
parent | f97d1fb614ff7638d13eb7c552d2a72fce4c613a (diff) | |
download | haskell-66f5d6d634698ce054a9b9ce0c53ce9682f6f042.tar.gz |
Improve error handling for VTA + deferred type errors
This fixes #17792
See Note [VTA for out-of-scope functions] in TcExpr
-rw-r--r-- | compiler/typecheck/TcExpr.hs | 40 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/T17792.hs | 10 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/T17792.stderr | 3 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/all.T | 1 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/T13834.stderr | 3 |
5 files changed, 35 insertions, 22 deletions
diff --git a/compiler/typecheck/TcExpr.hs b/compiler/typecheck/TcExpr.hs index f5e92ffe7d..688e3797dc 100644 --- a/compiler/typecheck/TcExpr.hs +++ b/compiler/typecheck/TcExpr.hs @@ -1081,10 +1081,6 @@ isHsValArg (HsValArg {}) = True isHsValArg (HsTypeArg {}) = False isHsValArg (HsArgPar {}) = False -isHsTypeArg :: HsArg tm ty -> Bool -isHsTypeArg (HsTypeArg {}) = True -isHsTypeArg _ = False - isArgPar :: HsArg tm ty -> Bool isArgPar (HsArgPar {}) = True isArgPar (HsValArg {}) = False @@ -1219,14 +1215,6 @@ tcArgs :: LHsExpr GhcRn -- ^ The function itself (for err msgs only) -> TcM (HsWrapper, [LHsExprArgOut], TcSigmaType) -- ^ (a wrapper for the function, the tc'd args, result type) tcArgs fun orig_fun_ty fun_orig orig_args herald - | fun_is_out_of_scope - , any isHsTypeArg orig_args - = failM -- See Note [VTA for out-of-scope functions] - -- We have /already/ emitted a CHoleCan constraint (in tcInferFun), - -- which will later cough up a "Variable not in scope error", so - -- we can simply fail now, avoiding a confusing error cascade - - | otherwise = go [] 1 orig_fun_ty orig_args where -- Don't count visible type arguments when determining how many arguments @@ -1248,6 +1236,10 @@ tcArgs fun orig_fun_ty fun_orig orig_args herald } go acc_args n fun_ty (HsTypeArg l hs_ty_arg : args) + | fun_is_out_of_scope -- See Note [VTA for out-of-scope functions] + = go acc_args (n+1) fun_ty args + + | otherwise = do { (wrap1, upsilon_ty) <- topInstantiateInferred fun_orig fun_ty -- wrap1 :: fun_ty "->" upsilon_ty ; case tcSplitForAllTy_maybe upsilon_ty of @@ -1338,17 +1330,23 @@ generate an immediate failure (in tc_app_err), saying that a function of type 'alpha' can't be applied to Bool. That's insane! And indeed users complain bitterly (#13834, #17150.) -The right error is the CHoleCan, which reports 'wurble' as out of -scope, and tries to give its type. +The right error is the CHoleCan, which has /already/ been emitted by +tcUnboundId. It later reports 'wurble' as out of scope, and tries to +give its type. + +Fortunately in tcArgs we still have access to the function, so we can +check if it is a HsUnboundVar. We use this info to simply skip over +any visible type arguments. We've already inferred the type of the +function, so we'll /already/ have emitted a CHoleCan constraint; +failing preserves that constraint. -Fortunately in tcArgs we still have access to the function, so -we can check if it is a HsUnboundVar. If so, we simply fail -immediately. We've already inferred the type of the function, -so we'll /already/ have emitted a CHoleCan constraint; failing -preserves that constraint. +We do /not/ want to fail altogether in this case (via failM) becuase +that may abandon an entire instance decl, which (in the presence of +-fdefer-type-errors) leads to leading to #17792. -A mild shortcoming of this approach is that we thereby -don't typecheck any of the arguments, but so be it. +Downside; the typechecked term has lost its visible type arguments; we +don't even kind-check them. But let's jump that bridge if we come to +it. Meanwhile, let's not crash! Note [Visible type application zonk] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/testsuite/tests/typecheck/should_compile/T17792.hs b/testsuite/tests/typecheck/should_compile/T17792.hs new file mode 100644 index 0000000000..3b18f566c4 --- /dev/null +++ b/testsuite/tests/typecheck/should_compile/T17792.hs @@ -0,0 +1,10 @@ +{-# LANGUAGE TypeApplications #-} +{-# OPTIONS_GHC -fdefer-type-errors #-} + +module T17792 where + +class C a where + m :: a + +instance C Bool where + m = notInScope @Word diff --git a/testsuite/tests/typecheck/should_compile/T17792.stderr b/testsuite/tests/typecheck/should_compile/T17792.stderr new file mode 100644 index 0000000000..2c499f91b9 --- /dev/null +++ b/testsuite/tests/typecheck/should_compile/T17792.stderr @@ -0,0 +1,3 @@ + +T17792.hs:10:7: warning: [-Wdeferred-out-of-scope-variables (in -Wdefault)] + Variable not in scope: notInScope :: Bool diff --git a/testsuite/tests/typecheck/should_compile/all.T b/testsuite/tests/typecheck/should_compile/all.T index d143251f9b..c1cd076a6d 100644 --- a/testsuite/tests/typecheck/should_compile/all.T +++ b/testsuite/tests/typecheck/should_compile/all.T @@ -697,3 +697,4 @@ test('T17566', [extra_files(['T17566a.hs'])], makefile_test, []) test('T12760', unless(compiler_debugged(), skip), compile, ['-O']) test('T13142', normal, compile, ['-O2']) test('T12926', reqlib('vector'), compile, ['-O2']) +test('T17792', normal, compile, ['']) diff --git a/testsuite/tests/typecheck/should_fail/T13834.stderr b/testsuite/tests/typecheck/should_fail/T13834.stderr index 73d739ea87..864b5ab7ae 100644 --- a/testsuite/tests/typecheck/should_fail/T13834.stderr +++ b/testsuite/tests/typecheck/should_fail/T13834.stderr @@ -1,2 +1,3 @@ -T13834.hs:5:7: error: Variable not in scope: notInScope +T13834.hs:5:7: + Variable not in scope: notInScope :: Bool -> t |