Skip to content

Detect Attach effects during semantic scan - #1340

Merged
lionel- merged 2 commits into
mainfrom
oak-nse/2-attach
Aug 3, 2026
Merged

Detect Attach effects during semantic scan#1340
lionel- merged 2 commits into
mainfrom
oak-nse/2-attach

Conversation

@lionel-

@lionel- lionel- commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Progress towards #1338
Branched from #1339

This PR does two related things:

  • Recognise library() / require() Attach effects during the linear scan
  • Feed those attaches into imported effects resolution

This allows the following pattern to be correctly recognised:

library(shiny)
reactive(...)

It's all flow dependent and recognises locally bound and imported symbols as you'd expect:

local(library <- identity)
library(dplyr) # Attaches

library <- identity
library(dplyr) # Symbol not found

A new attached_flow state powers this feature. During the linear scan, it contains the eager flow prefix so that eager code sees eager effects. During the walk, it contains the EOF state which serves as an over-approximation for lazy contexts (similarly to how they see the union of all bindings via enclosing snapshots).

The PR also starts the work of abstracting "effects". I'm planning for all these to be effects that alter the construction of the semantic index:

  • NSE evaluation of arguments
  • Attaching a package to the global search path: library(), require()
  • Sourcing another file: source(), pkgload::load_code()
  • Quoting an argument: quote(), bquote()
  • Evaluating a quoted argument: eval()
  • Capturing an environment: new.env(), parent.frame()

I'm working towards two ways of declaring effects:

  • declare() annotations for simple patterns.
  • Custom handlers in a contrib/ folder in Oak that will have access to Oak's resolution machinery.

Simple patterns can still be somewhat complex with the language I'm toying with, e.g.:

library <- function(pkg, character.only = FALSE) {
  declare(
    Attach(if (.(character.only)) .(pkg) else .(substitute(pkg)))
  )
}

The .() means "whatever this statically resolves to" and should allow expressing a lot of patterns, in combination with if/else interpretation. However trying to express everything R functions do in the wild is a lost cause, so custom handlers will often be the pragmatic choice.

This PR introduces a new EffectHandler trait. The effect resolver in ImportsResolver now return these handlers and the builder runs them against a CallContext to get a resolved set of effects. The CallContext object allows the handlers to match arguments and resolve them to statically known values (it's still rudimentary).

LazyShadowAmbiguity now covers Attach as well as NSE so we can lint ambiguous code:

f <- function() library(shiny)
library <- identity

Positron Release Notes

New Features

  • Smarter handling of library() and require() calls.

Bug Fixes

  • N/A

@lionel- lionel- mentioned this pull request Jul 16, 2026
@lionel-
lionel- force-pushed the oak-nse/2-attach branch 4 times, most recently from 37a5e38 to b4c59e3 Compare July 22, 2026 12:46
@lionel-
lionel- force-pushed the oak-nse/2-attach branch 2 times, most recently from 50bdb1a to aecb84d Compare July 28, 2026 12:27
@lionel-
lionel- force-pushed the oak-nse/2-attach branch from aecb84d to fe443c0 Compare July 30, 2026 14:38
@lionel-
lionel- force-pushed the oak-nse/2-attach branch from fe443c0 to 9b2bc67 Compare July 31, 2026 07:08
@lionel-
lionel- force-pushed the oak-nse/2-attach branch 3 times, most recently from 3924bb5 to 8c6f3c5 Compare August 3, 2026 13:17
Base automatically changed from oak-nse/1-nested to main August 3, 2026 16:18
@lionel-
lionel- merged commit 55a302c into main Aug 3, 2026
17 checks passed
@lionel-
lionel- deleted the oak-nse/2-attach branch August 3, 2026 16:19
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant