Skip to content

Commit f2f077b

Browse files
committed
Unregister S3 methods explicitly
This is a workaround for a bug in base R. unloadNamespace does not unregister any S3 methods, so the promises are invalid if you install a new version of a package, try to unload and re-load the package. See https://stat.ethz.ch/pipermail/r-devel/2015-December/072150.html for more details and a reproducible example. This fixes the common lazy-load errors people often run into when trying to use devtools' install functions. Fixes r-lib#419, r-lib#503, r-lib#942, r-lib#631
1 parent 9aaa3af commit f2f077b

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

R/unload.r

+35-8
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,9 @@
3030
unload <- function(pkg = ".") {
3131
pkg <- as.package(pkg)
3232

33-
# This is a hack to work around unloading devtools itself. The unloading
34-
# process normally makes other devtools functions inaccessible,
35-
# resulting in "Error in unload(pkg) : internal error -3 in R_decompress1".
36-
# If we simply access them here using as.list (without calling them), then
37-
# they will remain available for use later.
38-
if (pkg$package == "devtools") {
39-
as.list(ns_env(pkg))
40-
}
33+
ns <- asNamespace(pkg$package)
34+
35+
unregister_S3_methods(ns)
4136

4237
# If the package was loaded with devtools, any s4 classes that were created
4338
# by the package need to be removed in a special way.
@@ -78,6 +73,38 @@ unload <- function(pkg = ".") {
7873
unload_dll(pkg)
7974
}
8075

76+
unregister_S3_methods <- function(ns) {
77+
S3_methods <- getNamespaceInfo(ns, "S3methods")
78+
79+
unregister <- function(name, class, method) {
80+
# This code was adapted from the .registerS3method internal function of
81+
# base::registerS3methods
82+
# https://github.com/wch/r-source/blob/05b76baa411afd3e9d0f3fc3c09a9a252a0a9100/src/library/base/R/namespace.R#L1398-L1426
83+
env <-
84+
if (!is.na(x <- .knownS3Generics[name])) {
85+
asNamespace(x)
86+
} else {
87+
if(is.null(genfun <- get0(name, envir = ns))) {
88+
stop(sprintf("object '%s' not found while unloading namespace '%s'",
89+
name, getNamespaceName(ns)), call. = FALSE)
90+
}
91+
if(.isMethodsDispatchOn() && methods::is(genfun, "genericFunction")) {
92+
genfun <- genfun@default # nearly always, the S3 generic
93+
}
94+
if (typeof(genfun) == "closure") {
95+
environment(genfun)
96+
} else {
97+
baseenv()
98+
}
99+
}
100+
table <- get(".__S3MethodsTable__.", envir = env, inherits = FALSE)
101+
rm(list = method, envir = table)
102+
}
103+
for (i in seq_len(NROW(S3_methods))) {
104+
unregister(S3_methods[i, 1], S3_methods[i, 2], S3_methods[i, 3])
105+
}
106+
}
107+
81108
# This unloads dlls loaded by either library() or load_all()
82109
unload_dll <- function(pkg = ".") {
83110
pkg <- as.package(pkg)

0 commit comments

Comments
 (0)