@@ -88,6 +88,7 @@ considered incompatible.
88
88
* [ Minor: generalizing a function to use generics (supporting original type)] ( #fn-generalize-compatible )
89
89
* [ Major: generalizing a function to use generics with type mismatch] ( #fn-generalize-mismatch )
90
90
* [ Minor: making an ` unsafe ` function safe] ( #fn-unsafe-safe )
91
+ * [ Major: adding a potentially shadowing method] ( #fn-add-potentially-shadowing-method )
91
92
* Attributes
92
93
* [ Major: switching from ` no_std ` support to requiring ` std ` ] ( #attr-no-std-to-std )
93
94
* [ Major: adding ` non_exhaustive ` to an existing enum, variant, or struct with no private fields] ( #attr-adding-non-exhaustive )
@@ -1883,6 +1884,137 @@ Making a previously `unsafe` associated function or method on structs / enums
1883
1884
safe is also a minor change, while the same is not true for associated
1884
1885
function on traits (see [ any change to trait item signatures] ( #trait-item-signature ) ).
1885
1886
1887
+ ### Major: add a potentially shadowing method {#fn-add-potentially-shadowing-method}
1888
+
1889
+ If you have a type which implements ` Deref<Target=T> ` , you must not add methods
1890
+ which may "shadow" methods in ` T ` . This can lead to unexpected changes in
1891
+ program behavior.
1892
+
1893
+ ``` rust,ignore,run-fail
1894
+ // MAJOR CHANGE
1895
+
1896
+ ///////////////////////////////////////////////////////////
1897
+ // Before
1898
+ #[derive(Clone, Copy)]
1899
+ pub struct MySmartPtr<T>(pub T);
1900
+
1901
+ impl<T> core::ops::Deref for MySmartPtr<T> {
1902
+ type Target = T;
1903
+ fn deref(&self) -> &Self::Target {
1904
+ &self.0
1905
+ }
1906
+ }
1907
+
1908
+ ///////////////////////////////////////////////////////////
1909
+ // After
1910
+ #[derive(Clone, Copy)]
1911
+ pub struct MySmartPtr<T>(pub T);
1912
+
1913
+ impl<T> core::ops::Deref for MySmartPtr<T> {
1914
+ type Target = T;
1915
+ fn deref(&self) -> &Self::Target {
1916
+ &self.0
1917
+ }
1918
+ }
1919
+
1920
+ impl<T> MySmartPtr<T> {
1921
+ pub fn method(self) -> usize {
1922
+ 2
1923
+ }
1924
+ }
1925
+
1926
+ ///////////////////////////////////////////////////////////
1927
+ // Example usage that will break.
1928
+ use updated_crate::MySmartPtr;
1929
+
1930
+ struct SomeStruct;
1931
+
1932
+ impl SomeStruct {
1933
+ fn method(&self) -> usize {
1934
+ 1
1935
+ }
1936
+ }
1937
+
1938
+ fn main() {
1939
+ let mut ptr = MySmartPtr(SomeStruct);
1940
+ assert_eq!(ptr.method(), 1);
1941
+ }
1942
+ ```
1943
+
1944
+ Note that the shadowing and shadowed methods receive ` self `
1945
+ slightly differently: ` &self ` and ` &mut self ` .
1946
+ That's because Rust searches for methods first by value, then by ` & ` , then
1947
+ by ` &mut T ` , then by ` *const T ` . Rust stops the search
1948
+ when it encounters a valid method, and so methods later in this order may
1949
+ be shadowed by methods encountered earlier.
1950
+
1951
+ This is only a compatibility risk if the ` Deref ` target is
1952
+ beyond your control. If your type implements ` Deref ` to another type where
1953
+ you can fix the available methods, you can ensure no shadowing
1954
+ occurs. An example is that ` PathBuf ` implements
1955
+ ` Deref<Target=Path> ` .
1956
+
1957
+ For types which do implement ` Deref ` with an arbitrary target,
1958
+ it's bad practice to add methods: add associated functions instead. This is
1959
+ the pattern used by Rust's standard library smart pointer types, such as
1960
+ ` Box ` , ` Rc ` and ` Arc ` .
1961
+
1962
+ Similar shadowing risks occur for a type implementing
1963
+ ` Receiver<Target=T> ` . If you have a type which implements either
1964
+ ` Receiver<Target=T> ` or ` Deref<Target=T> ` it may be used as a method receiver
1965
+ by ` T ` 's methods. If your type then adds a method, you may shadow methods in
1966
+ ` T ` . For instance:
1967
+
1968
+ ``` rust,ignore,skip
1969
+ // MAJOR CHANGE
1970
+
1971
+ ///////////////////////////////////////////////////////////
1972
+ // Before
1973
+ #![feature(arbitrary_self_types)]
1974
+ pub struct MySmartPtr<T>(pub T);
1975
+
1976
+ impl<T> core::ops::Receiver for MySmartPtr<T> {
1977
+ // or Deref
1978
+ type Target = T;
1979
+ }
1980
+
1981
+ ///////////////////////////////////////////////////////////
1982
+ // After
1983
+ #![feature(arbitrary_self_types)]
1984
+ pub struct MySmartPtr<T>(pub T);
1985
+
1986
+ impl<T> core::ops::Receiver for MySmartPtr<T> {
1987
+ // or Deref
1988
+ type Target = T;
1989
+ }
1990
+
1991
+ impl<T> MySmartPtr<T> {
1992
+ pub fn method(self) {}
1993
+ }
1994
+
1995
+ ///////////////////////////////////////////////////////////
1996
+ // Example usage that will break.
1997
+ #![feature(arbitrary_self_types)]
1998
+ use updated_crate::MySmartPtr;
1999
+
2000
+ struct SomeStruct;
2001
+
2002
+ impl SomeStruct {
2003
+ fn method(self: &MySmartPtr<Self>) {}
2004
+ }
2005
+
2006
+ fn main() {
2007
+ let ptr = MySmartPtr(SomeStruct);
2008
+ ptr.method(); // Error: multiple applicable items in scope
2009
+ }
2010
+ ```
2011
+
2012
+ When types like this are being used as method receivers, Rust endeavours to
2013
+ do additional searches and present errors in simple cases, e.g. shadowing of
2014
+ ` &self ` by ` self ` with inherent methods. This is better than invisible
2015
+ behavior changes - but either way it's a compatibility break. Avoid adding
2016
+ methods if you implement ` Deref ` or ` Receiver ` to an arbitrary target.
2017
+
1886
2018
### Major: switching from ` no_std ` support to requiring ` std ` {#attr-no-std-to-std}
1887
2019
1888
2020
If your library specifically supports a [ ` no_std ` ] environment, it is a
0 commit comments