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