summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2020-02-07 15:26:44 +0000
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-02-28 22:03:23 -0500
commit66f5d6d634698ce054a9b9ce0c53ce9682f6f042 (patch)
tree24225b89347cb0f32cff1f3921d71305f5fbdaab
parentf97d1fb614ff7638d13eb7c552d2a72fce4c613a (diff)
downloadhaskell-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.hs40
-rw-r--r--testsuite/tests/typecheck/should_compile/T17792.hs10
-rw-r--r--testsuite/tests/typecheck/should_compile/T17792.stderr3
-rw-r--r--testsuite/tests/typecheck/should_compile/all.T1
-rw-r--r--testsuite/tests/typecheck/should_fail/T13834.stderr3
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