|
6 | 6 | //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
|
7 | 7 | //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
|
8 | 8 |
|
| 9 | +use std::assert_matches::assert_matches; |
9 | 10 | use std::cell::RefCell;
|
10 | 11 | use std::fmt;
|
11 | 12 | use std::ops::ControlFlow;
|
@@ -890,12 +891,28 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
890 | 891 | fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) {
|
891 | 892 | match qpath {
|
892 | 893 | hir::QPath::Resolved(maybe_qself, path) => {
|
| 894 | + // Visit the path before the self type since computing the ambient object lifetime default |
| 895 | + // for the latter requires all lifetime arguments of the trait ref to be already resolved. |
| 896 | + self.visit_path(path, id); |
893 | 897 | if let Some(qself) = maybe_qself {
|
894 |
| - // FIXME: Actually determine the ambient object lifetime defaults for the self ty! |
895 |
| - let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope }; |
896 |
| - self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 898 | + let container = match path.res { |
| 899 | + Res::Def(DefKind::AssocTy, def_id) => Some(( |
| 900 | + self.tcx.parent(def_id), |
| 901 | + &path.segments[..path.segments.len() - 1], |
| 902 | + )), |
| 903 | + _ => None, |
| 904 | + }; |
| 905 | + let object_lifetime_defaults = |
| 906 | + container.map_or(Vec::new(), |(def_id, segs)| { |
| 907 | + self.compute_ambient_object_lifetime_defaults(def_id, segs) |
| 908 | + }); |
| 909 | + if let Some(<) = object_lifetime_defaults.get(0) { |
| 910 | + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; |
| 911 | + self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 912 | + } else { |
| 913 | + self.visit_ty_unambig(qself); |
| 914 | + } |
897 | 915 | }
|
898 |
| - self.visit_path(path, id); |
899 | 916 | }
|
900 | 917 | hir::QPath::TypeRelative(qself, segment) => {
|
901 | 918 | // Resolving object lifetime defaults for type-relative paths requires full
|
@@ -1060,51 +1077,53 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
1060 | 1077 | }
|
1061 | 1078 |
|
1062 | 1079 | fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
|
1063 |
| - let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else { |
1064 |
| - bug!("expected GenericParam for object_lifetime_default"); |
| 1080 | + // Scan the bounds and where-clauses on parameters to extract bounds of the form `T: 'a` |
| 1081 | + // so as to determine the `ObjectLifetimeDefault` for each type parameter. |
| 1082 | + |
| 1083 | + let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) { |
| 1084 | + hir::Node::GenericParam(param) => match param.source { |
| 1085 | + hir::GenericParamSource::Generics => { |
| 1086 | + assert_matches!(param.kind, GenericParamKind::Type { .. }); |
| 1087 | + (tcx.hir_get_generics(tcx.local_parent(param_def_id)).unwrap(), &[][..]) |
| 1088 | + } |
| 1089 | + hir::GenericParamSource::Binder => return ObjectLifetimeDefault::Empty, |
| 1090 | + }, |
| 1091 | + // For Self ty params |
| 1092 | + hir::Node::Item(&hir::Item { |
| 1093 | + kind: hir::ItemKind::Trait(_, _, _, generics, bounds, _), |
| 1094 | + .. |
| 1095 | + }) => (generics, bounds), |
| 1096 | + _ => bug!("`object_lifetime_default` must only be called on type parameters"), |
1065 | 1097 | };
|
1066 |
| - match param.source { |
1067 |
| - hir::GenericParamSource::Generics => { |
1068 |
| - let parent_def_id = tcx.local_parent(param_def_id); |
1069 |
| - let generics = tcx.hir_get_generics(parent_def_id).unwrap(); |
1070 |
| - |
1071 |
| - // Scan the bounds and where-clauses on parameters to extract bounds |
1072 |
| - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` |
1073 |
| - // for each type parameter. |
1074 |
| - match param.kind { |
1075 |
| - GenericParamKind::Type { .. } => { |
1076 |
| - let mut set = Set1::Empty; |
1077 |
| - |
1078 |
| - // Look for `type: ...` where clauses. |
1079 |
| - for bound in generics.bounds_for_param(param_def_id) { |
1080 |
| - // Ignore `for<'a> type: ...` as they can change what |
1081 |
| - // lifetimes mean (although we could "just" handle it). |
1082 |
| - if !bound.bound_generic_params.is_empty() { |
1083 |
| - continue; |
1084 |
| - } |
1085 | 1098 |
|
1086 |
| - for bound in bound.bounds { |
1087 |
| - if let hir::GenericBound::Outlives(lifetime) = bound { |
1088 |
| - set.insert(lifetime.kind); |
1089 |
| - } |
1090 |
| - } |
1091 |
| - } |
| 1099 | + let mut set = Set1::Empty; |
1092 | 1100 |
|
1093 |
| - match set { |
1094 |
| - Set1::Empty => ObjectLifetimeDefault::Empty, |
1095 |
| - Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
1096 |
| - Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
1097 |
| - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
1098 |
| - } |
1099 |
| - _ => ObjectLifetimeDefault::Ambiguous, |
1100 |
| - } |
1101 |
| - } |
1102 |
| - _ => { |
1103 |
| - bug!("object_lifetime_default must only be called on a type parameter") |
1104 |
| - } |
| 1101 | + let mut add_outlives_bounds = |bounds: &[hir::GenericBound<'_>]| { |
| 1102 | + for bound in bounds { |
| 1103 | + if let hir::GenericBound::Outlives(lifetime) = bound { |
| 1104 | + set.insert(lifetime.kind); |
1105 | 1105 | }
|
1106 | 1106 | }
|
1107 |
| - hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, |
| 1107 | + }; |
| 1108 | + |
| 1109 | + add_outlives_bounds(bounds); |
| 1110 | + |
| 1111 | + // Look for `Type: ...` where clauses. |
| 1112 | + for bound in generics.bounds_for_param(param_def_id) { |
| 1113 | + // Ignore `for<'a> Type: ...` as they can change what |
| 1114 | + // lifetimes mean (although we could "just" handle it). |
| 1115 | + if bound.bound_generic_params.is_empty() { |
| 1116 | + add_outlives_bounds(&bound.bounds); |
| 1117 | + } |
| 1118 | + } |
| 1119 | + |
| 1120 | + match set { |
| 1121 | + Set1::Empty => ObjectLifetimeDefault::Empty, |
| 1122 | + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
| 1123 | + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
| 1124 | + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
| 1125 | + } |
| 1126 | + _ => ObjectLifetimeDefault::Ambiguous, |
1108 | 1127 | }
|
1109 | 1128 | }
|
1110 | 1129 |
|
@@ -1684,106 +1703,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
1684 | 1703 |
|
1685 | 1704 | debug!(?container);
|
1686 | 1705 |
|
1687 |
| - // Compute a vector of ambient object lifetime defaults, one for each type parameter, |
1688 |
| - // per the rules initially given in RFCs 599 and 1156. Example: |
1689 |
| - // |
1690 |
| - // ```rust |
1691 |
| - // struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U); |
1692 |
| - // ``` |
1693 |
| - // |
1694 |
| - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default |
1695 |
| - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) |
1696 |
| - // and `dyn Baz` to `dyn Baz + 'static` (because there is no |
1697 |
| - // such bound). |
1698 |
| - // |
1699 |
| - // Therefore, we would compute a vector like `['x, 'static]`. |
1700 |
| - // Note that the vector only includes type parameters. |
1701 |
| - let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segments)| { |
1702 |
| - let in_body = { |
1703 |
| - let mut scope = self.scope; |
1704 |
| - loop { |
1705 |
| - match *scope { |
1706 |
| - Scope::Root { .. } => break false, |
1707 |
| - |
1708 |
| - Scope::Body { .. } => break true, |
1709 |
| - |
1710 |
| - Scope::Binder { s, .. } |
1711 |
| - | Scope::ObjectLifetimeDefault { s, .. } |
1712 |
| - | Scope::Opaque { s, .. } |
1713 |
| - | Scope::Supertrait { s, .. } |
1714 |
| - | Scope::TraitRefBoundary { s, .. } |
1715 |
| - | Scope::LateBoundary { s, .. } => { |
1716 |
| - scope = s; |
1717 |
| - } |
1718 |
| - } |
1719 |
| - } |
1720 |
| - }; |
1721 |
| - |
1722 |
| - let rbv = &self.rbv; |
1723 |
| - let generics = self.tcx.generics_of(def_id); |
1724 |
| - |
1725 |
| - let set_to_region = |set: ObjectLifetimeDefault| match set { |
1726 |
| - ObjectLifetimeDefault::Empty => { |
1727 |
| - if in_body { |
1728 |
| - None |
1729 |
| - } else { |
1730 |
| - Some(ResolvedArg::StaticLifetime) |
1731 |
| - } |
1732 |
| - } |
1733 |
| - ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
1734 |
| - ObjectLifetimeDefault::Param(param_def_id) => { |
1735 |
| - fn param_to_depth_and_index( |
1736 |
| - generics: &ty::Generics, |
1737 |
| - tcx: TyCtxt<'_>, |
1738 |
| - def_id: DefId, |
1739 |
| - ) -> (usize, usize) { |
1740 |
| - if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
1741 |
| - let has_self = generics.parent.is_none() && generics.has_self; |
1742 |
| - (0, index as usize - generics.parent_count - has_self as usize) |
1743 |
| - } else if let Some(parent) = generics.parent { |
1744 |
| - let parent = tcx.generics_of(parent); |
1745 |
| - let (depth, index) = param_to_depth_and_index(parent, tcx, def_id); |
1746 |
| - (depth + 1, index) |
1747 |
| - } else { |
1748 |
| - unreachable!() |
1749 |
| - } |
1750 |
| - } |
1751 |
| - |
1752 |
| - let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
1753 |
| - segments[segments.len() - depth - 1] |
1754 |
| - .args |
1755 |
| - .and_then(|args| args.args.get(index)) |
1756 |
| - .and_then(|arg| match arg { |
1757 |
| - GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(), |
1758 |
| - _ => None, |
1759 |
| - }) |
1760 |
| - } |
1761 |
| - ObjectLifetimeDefault::Ambiguous => None, |
1762 |
| - }; |
1763 |
| - generics |
1764 |
| - .own_params |
1765 |
| - .iter() |
1766 |
| - .filter_map(|param| { |
1767 |
| - match self.tcx.def_kind(param.def_id) { |
1768 |
| - // Generic consts don't impose any constraints. |
1769 |
| - // |
1770 |
| - // We still store a dummy value here to allow generic parameters |
1771 |
| - // in an arbitrary order. |
1772 |
| - DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
1773 |
| - DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), |
1774 |
| - // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter |
1775 |
| - // works. Ignore it because it can't have a meaningful lifetime default. |
1776 |
| - DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, |
1777 |
| - dk => bug!("unexpected def_kind {:?}", dk), |
1778 |
| - } |
1779 |
| - }) |
1780 |
| - .map(set_to_region) |
1781 |
| - .collect() |
| 1706 | + let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segs)| { |
| 1707 | + self.compute_ambient_object_lifetime_defaults(def_id, segs) |
1782 | 1708 | });
|
1783 | 1709 |
|
1784 | 1710 | debug!(?object_lifetime_defaults);
|
1785 | 1711 |
|
1786 |
| - let mut i = 0; |
| 1712 | + let has_self = container |
| 1713 | + .map(|(def_id, _)| self.tcx.generics_of(def_id)) |
| 1714 | + .is_some_and(|generics| generics.parent.is_none() && generics.has_self); |
| 1715 | + let mut i = has_self as usize; |
1787 | 1716 | for arg in generic_args.args {
|
1788 | 1717 | match arg {
|
1789 | 1718 | // We've already visited all lifetime arguments at the start.
|
@@ -1915,6 +1844,110 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
1915 | 1844 | }
|
1916 | 1845 | }
|
1917 | 1846 |
|
| 1847 | + /// Compute a vector of ambient object lifetime defaults, one for each type parameter, |
| 1848 | + /// per the rules initially given in RFCs 599 and 1156. |
| 1849 | + /// |
| 1850 | + /// # Example |
| 1851 | + /// |
| 1852 | + /// ```ignore (illustrative) |
| 1853 | + /// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U); |
| 1854 | + /// ``` |
| 1855 | + /// |
| 1856 | + /// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default |
| 1857 | + /// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) |
| 1858 | + /// and `dyn Baz` to `dyn Baz + 'static` (because there is no |
| 1859 | + /// such bound). |
| 1860 | + /// |
| 1861 | + /// Therefore, we would compute a vector like `['x, 'static]`. |
| 1862 | + /// Note that the vector only includes type parameters. |
| 1863 | + fn compute_ambient_object_lifetime_defaults( |
| 1864 | + &self, |
| 1865 | + def_id: DefId, |
| 1866 | + segments: &[hir::PathSegment<'_>], |
| 1867 | + ) -> Vec<Option<ResolvedArg>> { |
| 1868 | + let in_body = { |
| 1869 | + let mut scope = self.scope; |
| 1870 | + loop { |
| 1871 | + match *scope { |
| 1872 | + Scope::Root { .. } => break false, |
| 1873 | + |
| 1874 | + Scope::Body { .. } => break true, |
| 1875 | + |
| 1876 | + Scope::Binder { s, .. } |
| 1877 | + | Scope::ObjectLifetimeDefault { s, .. } |
| 1878 | + | Scope::Opaque { s, .. } |
| 1879 | + | Scope::Supertrait { s, .. } |
| 1880 | + | Scope::TraitRefBoundary { s, .. } |
| 1881 | + | Scope::LateBoundary { s, .. } => { |
| 1882 | + scope = s; |
| 1883 | + } |
| 1884 | + } |
| 1885 | + } |
| 1886 | + }; |
| 1887 | + |
| 1888 | + let generics = self.tcx.generics_of(def_id); |
| 1889 | + |
| 1890 | + let set_to_region = |set: ObjectLifetimeDefault| match set { |
| 1891 | + ObjectLifetimeDefault::Empty => { |
| 1892 | + if in_body { |
| 1893 | + None |
| 1894 | + } else { |
| 1895 | + Some(ResolvedArg::StaticLifetime) |
| 1896 | + } |
| 1897 | + } |
| 1898 | + ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
| 1899 | + ObjectLifetimeDefault::Param(param_def_id) => { |
| 1900 | + fn param_to_depth_and_index( |
| 1901 | + generics: &ty::Generics, |
| 1902 | + tcx: TyCtxt<'_>, |
| 1903 | + def_id: DefId, |
| 1904 | + ) -> (usize, usize) { |
| 1905 | + if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
| 1906 | + let has_self = generics.parent.is_none() && generics.has_self; |
| 1907 | + (0, index as usize - generics.parent_count - has_self as usize) |
| 1908 | + } else if let Some(parent) = generics.parent { |
| 1909 | + let parent = tcx.generics_of(parent); |
| 1910 | + let (depth, index) = param_to_depth_and_index(parent, tcx, def_id); |
| 1911 | + (depth + 1, index) |
| 1912 | + } else { |
| 1913 | + unreachable!() |
| 1914 | + } |
| 1915 | + } |
| 1916 | + |
| 1917 | + let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
| 1918 | + segments[segments.len() - depth - 1] |
| 1919 | + .args |
| 1920 | + .and_then(|args| args.args.get(index)) |
| 1921 | + .and_then(|arg| match arg { |
| 1922 | + GenericArg::Lifetime(lt) => self.rbv.defs.get(<.hir_id.local_id).copied(), |
| 1923 | + _ => None, |
| 1924 | + }) |
| 1925 | + } |
| 1926 | + ObjectLifetimeDefault::Ambiguous => None, |
| 1927 | + }; |
| 1928 | + generics |
| 1929 | + .own_params |
| 1930 | + .iter() |
| 1931 | + .filter_map(|param| { |
| 1932 | + match self.tcx.def_kind(param.def_id) { |
| 1933 | + // Generic consts don't impose any constraints. |
| 1934 | + // |
| 1935 | + // We still store a dummy value here to allow generic parameters |
| 1936 | + // in an arbitrary order. |
| 1937 | + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
| 1938 | + // `Self` type params share the `DefId` of the corresp. trait. |
| 1939 | + DefKind::TyParam | DefKind::Trait => { |
| 1940 | + Some(self.tcx.object_lifetime_default(param.def_id)) |
| 1941 | + } |
| 1942 | + // `Self` type params of trait aliases may show up here, ignore them. |
| 1943 | + DefKind::LifetimeParam | DefKind::TraitAlias => None, |
| 1944 | + dk => bug!("unexpected def_kind {:?}", dk), |
| 1945 | + } |
| 1946 | + }) |
| 1947 | + .map(set_to_region) |
| 1948 | + .collect() |
| 1949 | + } |
| 1950 | + |
1918 | 1951 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the
|
1919 | 1952 | /// associated type name and starting trait.
|
1920 | 1953 | /// For example, imagine we have
|
|
0 commit comments