diff --git a/extra_tests/snippets/bytes.py b/extra_tests/snippets/bytes.py index 00723ad94..a4816984d 100644 --- a/extra_tests/snippets/bytes.py +++ b/extra_tests/snippets/bytes.py @@ -633,7 +633,8 @@ a = b'123abc!?' assert id(a) == id(a) assert id(a) != id(a * -1) assert id(a) != id(a * 0) -assert id(a) == id(a * 1) # only case when `id` stays the same +assert id(a) == id(a * 1) # only cases +assert id(a) == id(1 * a) # when `id` stays the same assert id(a) != id(a * 2) diff --git a/extra_tests/snippets/strings.py b/extra_tests/snippets/strings.py index 070d215de..12060fc40 100644 --- a/extra_tests/snippets/strings.py +++ b/extra_tests/snippets/strings.py @@ -632,7 +632,7 @@ def test_removeprefix(): assert s_uc.removeprefix('😱') == s_ref_uc[1:] assert s_uc.removeprefix('😱fo') == s_ref_uc[3:] assert s_uc.removeprefix('😱foo') == s_ref_uc[4:] - + assert s_uc.removeprefix('🖖') == s_ref_uc assert s_uc.removeprefix('foo') == s_ref_uc assert s_uc.removeprefix(' ') == s_ref_uc @@ -676,7 +676,7 @@ def test_removesuffix(): assert s_uc.removesuffix('🖖') == s_ref_uc[:-1] assert s_uc.removesuffix('oo🖖') == s_ref_uc[:-3] assert s_uc.removesuffix('foo🖖') == s_ref_uc[:-4] - + assert s_uc.removesuffix('😱') == s_ref_uc assert s_uc.removesuffix('foo') == s_ref_uc assert s_uc.removesuffix(' ') == s_ref_uc @@ -702,3 +702,28 @@ skip_if_unsupported(3,9,test_removeprefix) skip_if_unsupported(3,9,test_removeprefix_types) skip_if_unsupported(3,9,test_removesuffix) skip_if_unsupported(3,9,test_removesuffix_types) + + +# Regression to +# https://github.com/RustPython/RustPython/issues/2840 + +a = 'abc123()' + +assert id(a) == id(a) +assert id(a) != id(a * -1) +assert id(a) != id(a * 0) +assert id(a) == id(a * 1) # only cases +assert id(a) == id(1 * a) # when `id` stays the same +assert id(a) != id(a * 2) + + +class MyString(str): + pass + +b = MyString('0123abc*&') +assert id(b) == id(b) +assert id(b) != id(b * -1) +assert id(b) != id(b * 0) +assert id(b) != id(b * 1) +assert id(b) != id(1 * b) +assert id(b) != id(b * 2) diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/pystr.rs index 25935fcd1..39dede033 100644 --- a/vm/src/builtins/pystr.rs +++ b/vm/src/builtins/pystr.rs @@ -329,8 +329,15 @@ impl PyStr { #[pymethod(name = "__rmul__")] #[pymethod(magic)] - fn mul(&self, value: isize) -> String { - self.value.repeat(value.to_usize().unwrap_or(0)) + fn mul(zelf: PyRef, value: isize, vm: &VirtualMachine) -> PyRef { + if value == 1 && zelf.class().is(&vm.ctx.types.str_type) { + // Special case: when some `str` is multiplied by `1`, + // nothing really happens, we need to return an object itself + // with the same `id()` to be compatible with CPython. + // This only works for `str` itself, not its subclasses. + return zelf; + } + Self::from(zelf.value.repeat(value.to_usize().unwrap_or(0))).into_ref(vm) } #[pymethod(magic)]