Skip to content

Commit 4afea2f

Browse files
Fix VTAs wildcard inferred warning (#4492)
The problem initially arises when we convert the [`ExprVisibleApp` (CST value) into `VisibleTypeApp` (AST value)](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/CST/Convert.hs#L338-L340). Using [`convertType`](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/CST/Convert.hs#L122-L123), whenever we come across a wildcard, we always convert the resulting value into an `UnnamedWildcard`. Later, [right before we typecheck a module's declarations](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/TypeChecker.hs#L614), we update all `UnnamedWildcard` to `IgnoreWildcard` if they appear in a specific context via [`ignoreWildcardsUnderCompleteTypeSignatures`](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/Linter/Wildcards.hs#L10-L47). Because Visible Type Applications are a separate concept, they aren't converted here. Presumably, while typechecking, the compiler emits a warning for each `UnnamedWildcard` found, which produces the issue. Thus, there are two ways to resolve this: 1. (this PR) we update `convertType` to take another arg indicating whether it was called while converting an `ExprVisibleApp` into a `VisibleTypeApp`. If it was, then convert any wildcards into `IgnoreWildcard` in the first place. This solves the root of the problem but any other usages of `convertType` don't have this special rule in place. 1. (not this PR) we update the `ignoreWildcards*` function to also account for `VisibleTypeApp`. This is a smaller change but comes at the cost of another traversal through the AST. AFAICT, `convertType` is only used in two other places, both of which I think aren't affected by this change: - [Ide/CaseSplit.hs](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/Ide/CaseSplit.hs#L128) - [Interactive/Parser.hs](https://github.com/purescript/purescript/blob/master/src/Language/PureScript/Interactive/Parser.hs#L108) Lastly, we call into `convertType` via the conversion of `ExprVisibleApp` to `VisibleTypeApp`, However, `convertType` can also call `convertConstraint`, which calls `convertType`. Thus, `convertConstraint` needs to propagate the `withinVta` arg as well.
1 parent 9074fc6 commit 4afea2f

File tree

4 files changed

+56
-10
lines changed

4 files changed

+56
-10
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
* Stop emitting warnings for wildcards in Visible Type Applications
2+
3+
Previously, the below usage of a wildcard (i.e. `_`) would
4+
incorrectly cause the compiler to emit a warning.
5+
6+
```purs
7+
f :: forall @a. a -> a
8+
f = identity
9+
10+
x :: { x :: Int }
11+
x = f @{ x :: _ } { x: 42 }
12+
```

src/Language/PureScript/CST/Convert.hs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,13 @@ ident :: Ident -> N.Ident
9898
ident = N.Ident . getIdent
9999

100100
convertType :: String -> Type a -> T.SourceType
101-
convertType fileName = go
101+
convertType = convertType' False
102+
103+
convertVtaType :: String -> Type a -> T.SourceType
104+
convertVtaType = convertType' True
105+
106+
convertType' :: Bool -> String -> Type a -> T.SourceType
107+
convertType' withinVta fileName = go
102108
where
103109
goRow (Row labels tl) b = do
104110
let
@@ -120,7 +126,7 @@ convertType fileName = go
120126
TypeConstructor _ a ->
121127
T.TypeConstructor (sourceQualName fileName a) $ qualified a
122128
TypeWildcard _ a ->
123-
T.TypeWildcard (sourceAnnCommented fileName a a) T.UnnamedWildcard
129+
T.TypeWildcard (sourceAnnCommented fileName a a) $ if withinVta then T.IgnoredWildcard else T.UnnamedWildcard
124130
TypeHole _ a ->
125131
T.TypeWildcard (sourceName fileName a) . T.HoleWildcard . getIdent $ nameValue a
126132
TypeString _ a b ->
@@ -182,7 +188,7 @@ convertType fileName = go
182188
Env.tyFunction $> sourceAnnCommented fileName a a
183189
TypeConstrained _ a _ b -> do
184190
let
185-
a' = convertConstraint fileName a
191+
a' = convertConstraint withinVta fileName a
186192
b' = go b
187193
ann = Pos.widenSourceAnn (T.constraintAnn a') (T.getAnnForType b')
188194
T.ConstrainedType ann a' b'
@@ -195,13 +201,13 @@ convertType fileName = go
195201
ann = uncurry (sourceAnnCommented fileName) rng
196202
T.setAnnForType ann $ Env.kindRow a'
197203

198-
convertConstraint :: String -> Constraint a -> T.SourceConstraint
199-
convertConstraint fileName = go
204+
convertConstraint :: Bool -> String -> Constraint a -> T.SourceConstraint
205+
convertConstraint withinVta fileName = go
200206
where
201207
go = \case
202208
cst@(Constraint _ name args) -> do
203209
let ann = uncurry (sourceAnnCommented fileName) $ constraintRange cst
204-
T.Constraint ann (qualified name) [] (convertType fileName <$> args) Nothing
210+
T.Constraint ann (qualified name) [] (convertType' withinVta fileName <$> args) Nothing
205211
ConstraintParens _ (Wrapped _ c _) -> go c
206212

207213
convertGuarded :: String -> Guarded a -> [AST.GuardedExpr]
@@ -337,7 +343,7 @@ convertExpr fileName = go
337343
positioned ann $ AST.App (go a) (go b)
338344
expr@(ExprVisibleTypeApp _ a _ b) -> do
339345
let ann = uncurry (sourceAnn fileName) $ exprRange expr
340-
positioned ann $ AST.VisibleTypeApp (go a) (convertType fileName b)
346+
positioned ann $ AST.VisibleTypeApp (go a) (convertVtaType fileName b)
341347
expr@(ExprLambda _ (Lambda _ as _ b)) -> do
342348
let ann = uncurry (sourceAnnCommented fileName) $ exprRange expr
343349
positioned ann
@@ -472,7 +478,7 @@ convertDeclaration fileName decl = case decl of
472478
pure $ AST.TypeClassDeclaration ann
473479
(nameValue name)
474480
(goTypeVar <$> vars)
475-
(convertConstraint fileName <$> maybe [] (toList . fst) sup)
481+
(convertConstraint False fileName <$> maybe [] (toList . fst) sup)
476482
(goFundep <$> maybe [] (toList . snd) fdeps)
477483
(goSig <$> maybe [] (NE.toList . snd) bd)
478484
DeclInstanceChain _ insts -> do
@@ -483,7 +489,7 @@ convertDeclaration fileName decl = case decl of
483489
clsAnn = findInstanceAnn cls args
484490
AST.TypeInstanceDeclaration ann' clsAnn chainId ix
485491
(mkPartialInstanceName nameSep cls args)
486-
(convertConstraint fileName <$> maybe [] (toList . fst) ctrs)
492+
(convertConstraint False fileName <$> maybe [] (toList . fst) ctrs)
487493
(qualified cls)
488494
(convertType fileName <$> args)
489495
(AST.ExplicitInstance $ goInstanceBinding <$> maybe [] (NE.toList . snd) bd)
@@ -497,7 +503,7 @@ convertDeclaration fileName decl = case decl of
497503
| otherwise = AST.DerivedInstance
498504
clsAnn = findInstanceAnn cls args
499505
pure $ AST.TypeInstanceDeclaration ann clsAnn chainId 0 name'
500-
(convertConstraint fileName <$> maybe [] (toList . fst) ctrs)
506+
(convertConstraint False fileName <$> maybe [] (toList . fst) ctrs)
501507
(qualified cls)
502508
(convertType fileName <$> args)
503509
instTy

tests/purs/warning/VTAsWildcardInferred.out

Whitespace-only changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- See https://github.com/purescript/purescript/issues/4487
2+
module Main where
3+
4+
import Prelude
5+
import Effect (Effect)
6+
import Effect.Console (log)
7+
8+
f :: forall @a. a -> a
9+
f = identity
10+
11+
test1 :: { x :: Int }
12+
test1 = f @{ x :: _ } { x: 42 }
13+
14+
class Foo :: Type -> Type -> Type -> Constraint
15+
class Foo a b c | a -> b c where
16+
fooMember :: a -> b
17+
18+
wrap :: forall @a. Array a -> Array (Array a)
19+
wrap as = [as]
20+
21+
arrFooMember :: forall c. Array (Foo Int Boolean c => Int -> Boolean)
22+
arrFooMember = [fooMember]
23+
24+
test2 :: forall c. Array (Array (Foo Int Boolean c => Int -> Boolean))
25+
test2 = wrap @(Foo Int Boolean _ => _) arrFooMember -- neither wildcard should warn IMO
26+
27+
main :: Effect Unit
28+
main = log "Done"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy