diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
index 5e5e1c83c8ccae8f9d443739fd9bb5b15b5681d9..c9baefdb00e4c3eaa15eb028458d5ee2468b3bd7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
@@ -604,7 +604,8 @@ public class ArgumentMatcher {
                     }
                     if (!matchedSuppliedArgs[suppliedIndex]) {
                         String suppliedName = signature.getName(suppliedIndex);
-                        if (suppliedName == null || suppliedName.isEmpty() || formalSignature.getName(formalIndex).isEmpty()) {
+                        String formalName = formalSignature.getName(formalIndex);
+                        if (suppliedName == null || suppliedName.isEmpty() || formalName == null || formalName.isEmpty()) {
                             // unnamed parameter, match by position
                             break;
                         }
@@ -732,6 +733,10 @@ public class ArgumentMatcher {
 
     /**
      * Searches for partial match of suppliedName inside formalNames and returns its (formal) index.
+     * If there are no varagrs and no match is found for given named actual argument, then this
+     * method raises "unused argument" error. However, if there are any null formal arguments, which
+     * may only happen in the case of builtins, then we let the argument matching proceed to
+     * positional matching. This situation may happen in S4 dispatch to a builtin, e.g. {@code $<-}.
      *
      * @return The position of the given suppliedName inside the formalNames. Throws errors if the
      *         argument has been matched before
@@ -739,6 +744,7 @@ public class ArgumentMatcher {
     private static <T> int findParameterPositionByPartialName(ArgumentsSignature formalsSignature, boolean[] formalsMatchedByExactName, String suppliedName, int[] resultPermutation, int suppliedIndex,
                     boolean hasVarArgs, RBaseNode callingNode, int varArgIndex, IntFunction<String> errorString) {
         assert suppliedName != null && !suppliedName.isEmpty();
+        boolean hasNullFormal = false;
         int found = MatchPermutation.UNMATCHED;
         for (int i = 0; i < formalsSignature.getLength(); i++) {
             if (formalsMatchedByExactName[i]) {
@@ -747,6 +753,7 @@ public class ArgumentMatcher {
             }
 
             String formalName = formalsSignature.getName(i);
+            hasNullFormal |= formalName == null;
             if (formalName != null) {
                 if (formalName.startsWith(suppliedName) && ((varArgIndex != ArgumentsSignature.NO_VARARG && i < varArgIndex) || varArgIndex == ArgumentsSignature.NO_VARARG)) {
                     // partial-match only if the formal argument is positioned before ...
@@ -760,7 +767,7 @@ public class ArgumentMatcher {
                 }
             }
         }
-        if (found >= 0 || hasVarArgs) {
+        if (found >= 0 || hasVarArgs || hasNullFormal) {
             return found;
         }
         throw callingNode.error(RError.Message.UNUSED_ARGUMENT, errorString.apply(suppliedIndex));
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 8bd5b6e68b9563df6f49186b63f669d347e3d5a5..ed3a0521e0794dc3f0509e3c8b4ecf8a73e5b374 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -80639,6 +80639,12 @@ Error in rnorm(s = 1, s = 1) :
 #{ f <- match.fun(length) ; f(c(1,2,3)) }
 [1] 3
 
+##com.oracle.truffle.r.test.functions.TestFunctions.testMatching#
+#`$<-`(someNonesense = list(), anotherNonesense = 'foo', 42)
+$foo
+[1] 42
+
+
 ##com.oracle.truffle.r.test.functions.TestFunctions.testMatching#
 #list(`...`=NULL);
 $...
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
index 00c2f892ebbf33e9aaafe888689c8a07691ddfee..753308f58bab44b4d5610cdac02aae83f1ffce54 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
@@ -259,6 +259,7 @@ public class TestFunctions extends TestBase {
         // however, two partial matches produce error, even if one is "longer"
         assertEval("{ foo <- function(xaaa, ...) list(xaa=xaaa, ...); foo(xa=4,xaa=5); }");
         assertEval("list(`...`=NULL);");
+        assertEval("`$<-`(someNonesense = list(), anotherNonesense = 'foo', 42)");
     }
 
     @Test