Skip to content

Commit 845c4e8

Browse files
committed
Detect missing 'do' and provide a hint
1 parent 108ed55 commit 845c4e8

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

parser-typechecker/src/Unison/PrintError.hs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import Unison.Syntax.TermPrinter qualified as TermPrinter
6464
import Unison.Term qualified as Term
6565
import Unison.Type (Type)
6666
import Unison.Type qualified as Type
67+
import Unison.Typechecker qualified as Typechecker
6768
import Unison.Typechecker.Context qualified as C
6869
import Unison.Typechecker.TypeError
6970
import Unison.Typechecker.TypeVar qualified as TypeVar
@@ -369,7 +370,7 @@ renderTypeError e env src = case e of
369370
Mismatch {..} ->
370371
mconcat
371372
[ Pr.lines
372-
[ "I found a value of type: " <> style Type1 (renderType' env foundLeaf),
373+
[ "I found a value of type: " <> style Type1 (renderType' env foundLeaf),
373374
"where I expected to find: " <> style Type2 (renderType' env expectedLeaf)
374375
],
375376
"\n\n",
@@ -387,6 +388,7 @@ renderTypeError e env src = case e of
387388
src
388389
[styleAnnotated Type1 foundLeaf]
389390
[styleAnnotated Type2 expectedLeaf],
391+
missingDelayHint,
390392
unitHint,
391393
intLiteralSyntaxTip mismatchSite expectedType,
392394
debugNoteLoc
@@ -407,6 +409,20 @@ renderTypeError e env src = case e of
407409
debugSummary note
408410
]
409411
where
412+
missingDelayHint = case Typechecker.isMismatchMissingDelay foundType expectedType of
413+
Nothing -> ""
414+
Just (Left _) ->
415+
Pr.lines
416+
[ "I expected the expression to be delayed, but it was not.",
417+
"Are you missing a `do`?"
418+
]
419+
Just (Right _) ->
420+
Pr.lines
421+
[ "",
422+
"I didn't expect this expression to be delayed, but it was.",
423+
"Are you using a `do` where you don't need one,",
424+
"or are you missing a `()` to force an expression?"
425+
]
410426
unitHintMsg =
411427
"\nHint: Actions within a block must have type "
412428
<> style Type2 (renderType' env expectedLeaf)

parser-typechecker/src/Unison/Typechecker.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Unison.Typechecker
1010
isEqual,
1111
isSubtype,
1212
fitsScheme,
13+
isMismatchMissingDelay,
1314
Env (..),
1415
Notes (..),
1516
Resolution (..),
@@ -38,6 +39,7 @@ import Data.Text qualified as Text
3839
import Data.Tuple qualified as Tuple
3940
import Unison.ABT qualified as ABT
4041
import Unison.Blank qualified as B
42+
import Unison.Builtin.Decls qualified as BuiltinDecls
4143
import Unison.Codebase.BuiltinAnnotation (BuiltinAnnotation)
4244
import Unison.Name qualified as Name
4345
import Unison.Prelude
@@ -48,6 +50,7 @@ import Unison.Syntax.Name qualified as Name (unsafeParseText, unsafeParseVar)
4850
import Unison.Term (Term)
4951
import Unison.Term qualified as Term
5052
import Unison.Type (Type)
53+
import Unison.Type qualified as Type
5154
import Unison.Typechecker.Context qualified as Context
5255
import Unison.Typechecker.TypeLookup qualified as TL
5356
import Unison.Typechecker.TypeVar qualified as TypeVar
@@ -405,3 +408,13 @@ wellTyped ppe env term = go <$> runResultT (synthesize ppe Context.PatternMatchC
405408
-- `forall a b . a -> b -> a` to be different types
406409
-- equals :: Var v => Type v -> Type v -> Bool
407410
-- equals t1 t2 = isSubtype t1 t2 && isSubtype t2 t1
411+
412+
-- | Checks if the mismatch between two types is due to a missing delay, if so returns a tag for which type is
413+
-- missing the delay
414+
isMismatchMissingDelay :: (Var v) => Type v loc -> Type v loc -> Maybe (Either (Type v loc) (Type v loc))
415+
isMismatchMissingDelay typeA typeB
416+
| isSubtype (Type.arrow () (Type.ref () BuiltinDecls.unitRef) (typeA $> ())) (typeB $> ()) =
417+
Just (Left typeA)
418+
| isSubtype (ABT.tm (ABT.tm (Type.Ref BuiltinDecls.unitRef) `Type.Arrow` (typeB $> ()))) (typeA $> ()) =
419+
Just (Right typeB)
420+
| otherwise = Nothing

unison-cli/src/Unison/LSP/FileAnalysis.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import Unison.Syntax.Name qualified as Name
6262
import Unison.Syntax.Parser qualified as Parser
6363
import Unison.Syntax.TypePrinter qualified as TypePrinter
6464
import Unison.Term qualified as Term
65+
import Unison.Typechecker qualified as Typechecker
6566
import Unison.Typechecker.Context qualified as Context
6667
import Unison.Typechecker.TypeError qualified as TypeError
6768
import Unison.UnisonFile qualified as UF
@@ -224,7 +225,12 @@ analyseNotes codebase fileUri ppe src notes = do
224225
Result.TypeError errNote@(Context.ErrorNote {cause}) -> do
225226
let typeErr = TypeError.typeErrorFromNote errNote
226227
ranges = case typeErr of
227-
TypeError.Mismatch {mismatchSite} -> leafNodeRanges "mismatch" mismatchSite
228+
TypeError.Mismatch {mismatchSite, foundType, expectedType}
229+
| -- If it's a delay mismatch, the error is likely with the block definition (e.g. missing 'do') so we highlight the whole block.
230+
Just _ <- Typechecker.isMismatchMissingDelay foundType expectedType ->
231+
singleRange $ ABT.annotation mismatchSite
232+
-- Otherwise we highlight the leafe nodes of the block
233+
| otherwise -> leafNodeRanges "mismatch" mismatchSite
228234
TypeError.BooleanMismatch {mismatchSite} -> leafNodeRanges "mismatch" mismatchSite
229235
TypeError.ExistentialMismatch {mismatchSite} -> leafNodeRanges "mismatch" mismatchSite
230236
TypeError.FunctionApplication {f} -> singleRange $ ABT.annotation f

0 commit comments

Comments
 (0)