Conversation
|
We're no longer checking |
| -- contrast to the focused, local transformations provided by the zipper. | ||
|
|
||
| -- | Find all nodes at which the given variable is shadowed. | ||
| checkShadowing :: (Data a, Data b) => TmVarRef -> Expr' a b -> [a] |
There was a problem hiding this comment.
This seems like it will be useful again in future e.g. if we want to enumerate the shadowing sites for use in a GUI - see #332. But for now it only has one use site. There is already some similar-looking code in Primer.ZipperCxt, but as far as I can tell that's only concerned with walking up the tree, whereas here we only walk down. Maybe there's some way we can reuse that though? I'm not that comfortable with zippers.
There was a problem hiding this comment.
What should we return? I was thinking IDs, but that requires adding a HasID a constraint to renameVar and renameLocalVar. It doesn't bubble up any further than that, since the constraint is satisfied at every call site, but it feels wrong. renameVar doesn't even care what's in the list. I guess we could just return the whole expression?
2ea48db to
da0e0e0
Compare
Weeder rightly points out that it's unused, due to the changes to `renameVar` in the previous commit.
894063b to
98e6ce0
Compare
| -- | Find all nodes at which the given variable is shadowed. | ||
| checkShadowing :: (Data a, Data b) => TmVarRef -> Expr' a b -> [a] |
There was a problem hiding this comment.
I think here that we should be able to use Zipper.bindersBelow to see if the new name is bound.
There was a problem hiding this comment.
This would not check if the new name occurs free, but we can do that with one of the _freeVars optics (we should probably check both type and term vars). We need to avoid renaming x to y in C x y, as that changes the meaning.
There was a problem hiding this comment.
(I'm a bit worried here, as the testsuite passed. Either I've gotten confused, or we should add some extra testing here...)
| -- | Apply a function to all free occurrences of a variable. | ||
| transformVar :: | ||
| (Monad m, Data a, Data b') => | ||
| (a -> TmVarRef -> m (Expr' a b')) -> | ||
| TmVarRef -> | ||
| Expr' a b' -> | ||
| m (Expr' a b') | ||
| transformVar f x = \case |
There was a problem hiding this comment.
Can we reuse Core.Utils._freeTmVars here?
There was a problem hiding this comment.
Maybe.
The following doesn't work:
transformVar f x = traverseOf _freeTmVars $ \(m, LocalVarRef -> v) ->
if v == x then f m v else pure $ Var m v_freeTmVars doesn't find globals (should it?), so two tests fail (Tests.Action.Prog.rename def referenced and Tests.Action.Prog.rename def recursive).
There was a problem hiding this comment.
Hmm. Maybe we should add another traversal focussing on global vars and choose which to use when renaming based on the sort of var?
I expect said traversal should be easy to write using some generics, assuming we don't allow locals and globals to shadow. Alternatively it would be easy to change _freeTmVars to also return globals (and add a wrapper to only look at locals if we require).
| Var m v | ||
| | v == x -> pure m | ||
| | otherwise -> mempty |
There was a problem hiding this comment.
This does not seem correct: do you mean v == y?
There was a problem hiding this comment.
Ah, copy-paste error. This branch shouldn't exist. We're just using the variable: there's no shadowing.
PS. there's no y in scope.
There was a problem hiding this comment.
By y I mean "the new name" (but you're right, I didn't notice that it was not in scope here), and we need to do some check about it somewhere, see #378 (comment)
There was a problem hiding this comment.
The new name is the one we're checking here - note that renameVar calls this function with its y.
There was a problem hiding this comment.
Ah, thanks. This makes sense now.
brprice
left a comment
There was a problem hiding this comment.
This is the rough approach I had in mind, but I think we can reuse existing code, rather than writing new traversals.
It may be worth a comment about inefficiency traversing the tree twice, and in the future we could explore a "traversal-with-binding-info", which abstracts out the pattern "focus on bits of the tree and modify them, but keep track of what binders the focus is under". Perhaps something of the form freeVarsWithContext :: Traversal Expr Expr ({goneUnderBinders :: [Name], freeVariableOccurrunce :: Name}) Expr (although I have not thought about whether this is a law-abinding traversal, or of the best way to express the idea. Perhaps something zipper based?).
| unit_rename_def_capture = | ||
| progActionTest defaultEmptyProg [MoveToDef "other", BodyAction [ConstructLam $ Just "foo"], RenameDef "main" "foo"] $ | ||
| expectError (@?= ActionError NameCapture) | ||
| expectSuccess mempty |
There was a problem hiding this comment.
This is probably not what we want - it's just the simplest way to get tests to pass.
|
This is clearly more subtle then I originally hoped, and it turns out FWIW, I think this is genuinely a safe refactor (modulo checking between different scopes - #378 (comment)), but not quite for the reasons I thought. Essentially |
|
What's the status of this PR? I don't like to leave PRs open for very long and this one has been around going on 4 months. Sounds like it's no longer needed and/or not particularly useful so should we close it? |
|
As stated in the previous comment, it turned out to be quite complex, and the original issue was solved by other means. And I expect it may now be some effort to rebase on |
Inspired by a comment from @brprice on Keybase dev chat earlier today:
As implemented here, we don't "collect binders" in the first pass. I'm not quite sure what that would look like. Instead the first pass just performs the "checking they do not have the same name" part, and the second pass re-traverses the tree, performing the renaming.
The main intention is to reuse
transformVarto fix #367 (comment). Which is why that PR's branch is the target of this one.This needs a little cleaning up (including a better commit message, and possibly some tests), but I wanted to check that we're happy with the approach first.