@@ -1862,19 +1862,38 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
1862
1862
assert_eq ! ( old_value, Some ( bad_def) ) ;
1863
1863
}
1864
1864
1865
- // TODO:
1865
+ // When we have a return type notation type in a where clause, like
1866
+ // `where <T as Trait>::method(..): Send`, we need to introduce new bound
1867
+ // vars to the existing where clause's binder, to represent the lifetimes
1868
+ // elided by the return-type-notation syntax.
1869
+ //
1870
+ // For example, given
1871
+ // ```
1872
+ // trait Foo {
1873
+ // async fn x<'r, T>();
1874
+ // }
1875
+ // ```
1876
+ // and a bound that looks like:
1877
+ // `for<'a, 'b> <T as Trait<'a>>::x(): Other<'b>`
1878
+ // this is going to expand to something like:
1879
+ // `for<'a, 'b, 'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: Other<'b>`.
1880
+ //
1881
+ // We handle this similarly for associated-type-bound style return-type-notation
1882
+ // in `visit_segment_args`.
1866
1883
fn try_append_return_type_notation_params (
1867
1884
& mut self ,
1868
1885
hir_id : HirId ,
1869
1886
hir_ty : & ' tcx hir:: Ty < ' tcx > ,
1870
1887
) {
1871
1888
let hir:: TyKind :: Path ( qpath) = hir_ty. kind else {
1872
- // TODO:
1889
+ // We only care about path types here. All other self types
1890
+ // (including nesting the RTN type in another type) don't do
1891
+ // anything.
1873
1892
return ;
1874
1893
} ;
1875
1894
1876
1895
let ( mut bound_vars, item_def_id, item_segment) = match qpath {
1877
- // TODO:
1896
+ // If we have a fully qualified method, then we don't need to do any special lookup.
1878
1897
hir:: QPath :: Resolved ( _, path)
1879
1898
if let [ .., item_segment] = & path. segments [ ..]
1880
1899
&& item_segment. args . is_some_and ( |args| {
@@ -1890,23 +1909,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
1890
1909
( vec ! [ ] , item_def_id, item_segment)
1891
1910
}
1892
1911
1893
- // TODO:
1912
+ // If we have a type-dependent path, then we do need to do some lookup.
1894
1913
hir:: QPath :: TypeRelative ( qself, item_segment)
1895
1914
if item_segment. args . is_some_and ( |args| {
1896
1915
matches ! ( args. parenthesized, hir:: GenericArgsParentheses :: ReturnTypeNotation )
1897
1916
} ) =>
1898
1917
{
1918
+ // First, ignore a qself that isn't a type or `Self` param. Those are the
1919
+ // only ones that support `T::Assoc` anyways in HIR lowering.
1899
1920
let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind else {
1900
1921
return ;
1901
1922
} ;
1902
-
1903
1923
match path. res {
1904
1924
Res :: Def ( DefKind :: TyParam , _) | Res :: SelfTyParam { trait_ : _ } => {
1925
+ // Get the generics of this type's hir owner. This is *different*
1926
+ // from the generics of the parameter's definition, since we want
1927
+ // to be able to resolve an RTN path on a nested body (e.g. method
1928
+ // inside an impl) using the where clauses on the method.
1905
1929
let Some ( generics) = self . tcx . hir_owner_node ( hir_id. owner ) . generics ( )
1906
1930
else {
1907
1931
return ;
1908
1932
} ;
1909
1933
1934
+ // Look for the first bound that contains an associated type that
1935
+ // matches the segment that we're looking for. We ignore any subsequent
1936
+ // bounds since we'll be emitting a hard error in HIR lowering, so this
1937
+ // is purely speculative.
1910
1938
let one_bound = generics. predicates . iter ( ) . find_map ( |predicate| {
1911
1939
let hir:: WherePredicate :: BoundPredicate ( predicate) = predicate else {
1912
1940
return None ;
@@ -1944,7 +1972,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
1944
1972
_ => return ,
1945
1973
} ;
1946
1974
1947
- // TODO:
1975
+ // Append the early-bound vars on the function, and then the late-bound ones.
1976
+ // We actually turn type parameters into higher-ranked types here, but we
1977
+ // deny them later in HIR lowering.
1948
1978
bound_vars. extend ( self . tcx . generics_of ( item_def_id) . own_params . iter ( ) . map ( |param| {
1949
1979
match param. kind {
1950
1980
ty:: GenericParamDefKind :: Lifetime => ty:: BoundVariableKind :: Region (
@@ -1958,11 +1988,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
1958
1988
} ) ) ;
1959
1989
bound_vars. extend ( self . tcx . fn_sig ( item_def_id) . instantiate_identity ( ) . bound_vars ( ) ) ;
1960
1990
1961
- // TODO:
1991
+ // SUBTLE: Stash the old bound vars onto the *item segment* before appending
1992
+ // the new bound vars. We do this because we need to know how many bound vars
1993
+ // are present on the binder explicitly (i.e. not return-type-notation vars)
1994
+ // to do bound var shifting correctly in HIR lowering.
1962
1995
let existing_bound_vars = self . map . late_bound_vars . get_mut ( & hir_id) . unwrap ( ) ;
1963
1996
let existing_bound_vars_saved = existing_bound_vars. clone ( ) ;
1964
1997
existing_bound_vars. extend ( bound_vars) ;
1965
- // TODO: subtle
1966
1998
self . record_late_bound_vars ( item_segment. hir_id , existing_bound_vars_saved) ;
1967
1999
}
1968
2000
}
0 commit comments