diff --git a/R/S4.R b/R/S4.R index 88937ba9..f01179ba 100644 --- a/R/S4.R +++ b/R/S4.R @@ -45,13 +45,13 @@ S4_to_S7_class <- function(x, error_base = "", call = sys.call(-1L)) { # Convert generator function to class if (methods::is(x, "classGeneratorFunction")) { return(S4_to_S7_class( - methods::getClass(as.character(x@className)), + methods::getClass(x@className), error_base, call = call )) } - if (methods::is(x, "ClassUnionRepresentation")) { + if (methods::isClassUnion(x)) { subclasses <- Filter(function(y) y@distance == 1, x@subclasses) subclasses <- lapply(subclasses, function(x) methods::getClass(x@subClass)) do.call("new_union", subclasses) @@ -62,8 +62,8 @@ S4_to_S7_class <- function(x, error_base = "", call = sys.call(-1L)) { return(basic_classes[[x@className]]) } } - if (methods::extends(x, "oldClass")) { - new_S3_class(as.character(x@className)) + if (is_oldClass(x)) { + new_S3_class(methods::extends(x)) } else { x } @@ -129,7 +129,8 @@ S4_class_dispatch <- function(x) { } is_oldClass <- function(x) { - x@virtual && methods::extends(x, "oldClass") && x@className != "oldClass" + methods::extends(x, "oldClass") && + x@className %in% attr(x@prototype, ".S3Class") } S4_class_name <- function(x) { diff --git a/tests/testthat/test-S4.R b/tests/testthat/test-S4.R index 7b01a6a0..56c37210 100644 --- a/tests/testthat/test-S4.R +++ b/tests/testthat/test-S4.R @@ -124,6 +124,21 @@ describe("S4_class_dispatch", { ) }) + it("dispatches through the full S3 old-class hierarchy", { + on.exit(S4_remove_classes(c("S4OldS3Child", "S4OldS3a", "S4OldS3b"))) + + setOldClass(c("S4OldS3a", "S4OldS3b")) + setClass("S4OldS3Child", contains = "S4OldS3a") + + generic <- new_generic("S4OldS3Generic", "x") + method(generic, new_S3_class("S4OldS3b")) <- function(x) "S3 parent" + + object <- methods::new("S4OldS3Child") + + expect_contains(obj_dispatch(object), "S4OldS3b") + expect_equal(generic(object), "S3 parent") + }) + it("ignores unions", { on.exit(S4_remove_classes(c("Foo1", "Foo2", "Foo3")))